Не могли бы вы посоветовать мне лучший способ решения проблемы, с которой я столкнулся? Я знаю, что есть много способов снять шкуру с кошки. Я пробовал много разных способов, но, похоже, не нашел решения.
В итоге:
В моем приложении node js есть запрос на получение. Когда пользователь обращается к этому URL-адресу GET, я хочу, чтобы он получал записи для этого пользователя, однако, если их нет, я хочу создать набор записей для этого пользователя в соответствии с заранее определенным списком. (Мне нужно что-то вроде фабрика, чтобы создать пакет или записи и дать результаты, когда это будет сделано.)
Создание единой записи работает. Но мне нужно создать 4. Если я попытаюсь создать больше одного, я получу ...
UnhandledPromiseRejectionWarning: ошибка [ERR_HTTP_HEADERS_SENT]: невозможно установить заголовки после их отправки клиенту или просто ошибка в зависимости от того, какой вариант я использую.
По сути, как только вы создаете более 1 записи, создание этой записи возвращает ответ, который я хотел бы «объединить», и когда это будет сделано, отправить объединенный результат обратно.
Моя модель очень простая. Выглядит это так:
/*____ _ _ __ __ _ _
| _ \ | | | | | / | | | | |
| |_) |_ _ ___| | _____| |_ | \ / | ___ __| | ___| |
| _ <| | | |/ __| |/ / _ \ __| | |/| |/ _ \ / _` |/ _ \ |
| |_) | |_| | (__| < __/ |_ | | | | (_) | (_| | __/ |
|____/ \__,_|\___|_|\_\___|\__| |_| |_|\___/ \__,_|\___|_|
*/
const mongoose = require('mongoose');
const dbSchema = mongoose.Schema;
const bucketSchema = new dbSchema({
name: {
type: String,
required: true,
unique: false
},
createdby: {
type: dbSchema.Types.ObjectId,
ref: 'user'
},
createdon: {
type: Date,
default: Date.now
},
isforarchive: {
type: Boolean,
required: true,
default: false
},
cards: [
{
card: {
type: dbSchema.Types.ObjectId,
ref: 'card'
}
}
]
});
module.exports = bucket = mongoose.model('bucket', bucketSchema);
Этот код работает, когда я создаю одну запись. Однако мне нужно создать 4 сегмента для пользователя: - ToDo, Busy, Done и Archive.
Приведенный ниже код РАБОТАЕТ, НО СОЗДАЕТ ТОЛЬКО ОДИН ВЕДРО - ToDo.
const ToDo = new Bucket({
name: 'To-Do',
createdby: null,
createdon: Date.now(),
isforarchive: false,
cards: [ {} ]
});
// @route get:/api/tms/buckets
// @desc Gets user buckets or creates a set of buckets for the user if they do not exist.
// @access Private
router.get(
'/',
passport.authenticate('jwt', {
session: false
}),
(req, res) => {
console.info('About to search buckets...');
Bucket.find({ createdby: req.user.id })
.then((found) => {
console.info('Checking if found');
console.info(`Length ${found.length}`); // Zero when none found
if (found.length > 0) {
res.json(found);
} else {
console.info('Creating ToDo');
ToDo.createdby = req.user.id;
ToDo.save().then((saved) => res.json(saved));
}
})
.catch((err) => {
const errors = {};
errors.getbuckets = 'Encountered a problem getting buckets.';
errors.error = err;
res.status(400).json(errors);
});
}
);
Чтобы попытаться помочь мне, я создал вспомогательный класс ./buckethelper.js, чтобы помочь мне. Я пробовал обещания и т. д., Но не могу обойти проблему создания первой записи, отправляющей ответ, вызывающий указанную выше ошибку.
Я пробовал несколько разных вариантов в своем вспомогательном классе, но не могу заставить их работать. Я пытался обойти ряд проблем, одна из которых заключалась в том, что я хотел, чтобы код выполнялся синхронно и последовательно, а не параллельно.
Вот мой вспомогательный класс.
const Bucket = require('./model');
/*
//PLEASE NOTE THAT THIS SECTION IS COMMENTED OUT.
function CreateBucket(Name, CreatedBy, CreatedOn, IsForArchive, Cards) {
this.name = Name;
this.createdby = CreatedBy;
this.createdon = CreatedOn;
this.isforarchive = IsForArchive;
this.cards = Cards;
}
const Buckets = [];
Buckets.push(new CreateBucket('To-Do', '', Date.now(), false, [ {} ]));
Buckets.push(new CreateBucket('Busy', '', Date.now(), false, [ {} ]));
Buckets.push(new CreateBucket('Done', '', Date.now(), false, [ {} ]));
Buckets.push(new CreateBucket('Archive', '', Date.now(), true, [ {} ]));
*/
const ToDo = new Bucket({
name: 'To-Do',
createdby: null,
createdon: Date.now(),
isforarchive: false,
cards: [ {} ]
});
const Busy = new Bucket({
name: 'Busy',
createdby: null,
createdon: Date.now(),
isforarchive: false,
cards: [ {} ]
});
const Done = new Bucket({
name: 'Done',
createdby: null,
createdon: Date.now(),
isforarchive: false,
cards: [ {} ]
});
const Archive = new Bucket({
name: 'Archive',
createdby: null,
createdon: Date.now(),
isforarchive: true,
cards: [ {} ]
});
var result = [];
function fnSaveToDo(UserId) {
console.info(`Saving To Do ...`);
ToDo.createdby = UserId;
result.push(Bucket.save(ToDo));
}
function fnSaveBusy(UserId) {
Busy.createdby = UserId;
result.push(Bucket.insert(Busy));
}
function fnSaveDone(UserId) {
Done.createdby = UserId;
result.push(Bucket.insert(Done));
}
function fnSaveArchive(UserId) {
Archive.createdby = UserId;
result.push(Bucket.insert(Archive));
return result;//I want to return the combined results
}
//Synchronous call stack that execute in series not parallel
function CreateBuckets(UserId, fnSaveToDo, fnSaveBusy, fnSaveDone, fnSaveArchive) {
console.info('Started the saving process ...');
fnSaveToDo(UserId);
fnSaveBusy(UserId);
fnSaveDone(UserId);
fnSaveArchive(UserId);
}
CreateBuckets(
function() {
console.info('User id callback?');
},
function() {
console.info('ToDo saved ...');
},
function() {
console.info('Busy saved ...');
},
function() {
console.info('Done saved ...');
},
function() {
console.info('Archive saved ...');
}
);
module.exports = CreateBuckets;
Код, который вызывает моего помощника, выглядит примерно так, это подмножество приведенного выше кода;
Bucket.find({ createdby: req.user.id })
.then((found) => {
console.info('Checking if found');
console.info(`Length ${found.length}`); // Zero when none found
if (found.length > 0) {
res.json(found);
} else {
//console.info('Creating ToDo');
res.json(CreateBuckets(req.user.id,fnSaveToDo,fnSaveBusy, fnSaveDone, fnSaveArchive));
// ToDo.createdby = req.user.id;
// ToDo.save().then((saved) => res.json(saved));
}
})
.catch((err) => {
const errors = {};
errors.getbuckets = 'Encountered a problem getting buckets.';
errors.error = err;
res.status(400).json(errors);
});
Я надеюсь, что мое описание проблемы было ясным.
Если или когда я найду решение, я опубликую его. Я занимаюсь этим уже несколько дней без особого успеха.
С уважением Крейг





Вы можете использовать здесь метод insertMany, чтобы выполнить массовую вставку и использовать async / await в своих операциях, поскольку метод возвращает обещание.
Например, ваш маршрут можно переписать как
router.get('/', passport.authenticate('jwt', {session: false }), async (req, res) => {
try {
console.info('About to search buckets...');
const found = await Bucket.find({ createdby: req.user.id })
console.info('Checking if found');
console.info(`Length ${found.length}`); // Zero when none found
if (found.length > 0) {
res.json(found);
} else {
console.info('Creating ToDos');
const todos = ['To-Do', 'Busy', 'Done', 'Archive'].map(name => (
{
name,
createdby: req.user.id,
createdon: Date.now(),
isforarchive: (name == 'Archive'),
cards: [ {} ]
}
));
const saved = await ToDo.insertMany(todos);
res.json(saved);
}
} catch (err) {
const errors = {};
errors.getbuckets = 'Encountered a problem getting buckets.';
errors.error = err;
res.status(400).json(errors);
}
});
Спасибо за ваше решение. Однако я не мог заставить Ждите работать. Вот мое решение. Я проведу рефакторинг, но он работает.
const DefaultBuckets = [ 'To Do', 'Busy', 'Done', 'Archive' ];
// @route get:/api/tms/buckets
// @desc Gets user buckets or creates a set of buckets for the user if they do not exist.
// @access Private
router.get(
'/',
passport.authenticate('jwt', {
session: false
}),
(req, res) => {
console.info('About to search buckets...');
Bucket.find({ createdby: req.user.id })
.then((found) => {
console.info('Checking if found');
console.info(`Length ${found.length}`); // Zero when none found
if (found.length > 0) {
console.info('returning what is in db');
res.json(found);
} else {
// console.info('Creating buckets ...');
const defaults = DefaultBuckets.map((name) => ({
name,
createdby: req.user.id,
createdon: Date.now(),
isforarchive: name == 'Archive',
cards: [ {} ]
}));
Bucket.insertMany(defaults, (err, docs) => {
let errors = {};
// Docs are the saved records from the db
if (docs) {
res.json(docs);
}else{
errors.message = 'Could not create buckets';
errors.InsertMany = err;
res.status(400).json(errors);
}
});
}
})
.catch((err) => {
const errors = {};
errors.getbuckets = 'Encountered a problem getting buckets.';
errors.error = err;
res.status(400).json(errors);
});
}
);