Я не могу вручную или автоматически заполнить поле создателя на только что сохраненном объекте ... единственный способ, который я могу найти, - это повторно запросить объекты, которые у меня уже есть, что я бы не хотел делать.
Это установка:
var userSchema = new mongoose.Schema({
name: String,
});
var User = db.model('User', userSchema);
var bookSchema = new mongoose.Schema({
_creator: { type: mongoose.Schema.Types.ObjectId, ref: 'User' },
description: String,
});
var Book = db.model('Book', bookSchema);
Вот где я тяну за волосы
var user = new User();
user.save(function(err) {
var book = new Book({
_creator: user,
});
book.save(function(err){
console.log(book._creator); // is just an object id
book._creator = user; // still only attaches the object id due to Mongoose magic
console.log(book._creator); // Again: is just an object id
// I really want book._creator to be a user without having to go back to the db ... any suggestions?
});
});
РЕДАКТИРОВАТЬ: последний мангуст исправил эту проблему и добавил функцию заполнения, см. Новый принятый ответ.
creator.profile
В случае, если кто-то все еще ищет это.
В Mongoose 3.6 добавлено множество интересных функций:
book.populate('_creator', function(err) { console.log(book._creator); });
или:
Book.populate(book, '_creator', function(err) { console.log(book._creator); });
см. больше на: https://github.com/LearnBoost/mongoose/wiki/3.6-Release-Notes#population
Но таким образом вы все равно снова будете запрашивать пользователя.
Небольшой трюк, чтобы сделать это без дополнительных запросов:
источник
book._creator = user;
послеsave()
- это единственный правильный ответ среди всех текущих ответов, все остальные ответы требуют дополнительного запроса.Решением для меня было использовать
execPopulate
вот такconst t = new MyModel(value) return t.save().then(t => t.populate('my-path').execPopulate())
источник
Решение, которое возвращает обещание (без обратных вызовов):
Использовать документ № заполнить
book.populate('creator').execPopulate(); // summary doc.populate(options); // not executed doc.populate(options).execPopulate() // executed, returns promise
Возможная реализация
var populatedDoc = doc.populate(options).execPopulate(); var populatedDoc.then(doc => { ... });
О заполнении документа читайте здесь .
источник
Просто чтобы уточнить и привести еще один пример, поскольку он мне помог. Это может помочь тем, кто хочет получить частично заполненные объекты после сохранения. Метод тоже немного отличается. Потратил больше часа или двух на поиски правильного способа сделать это.
post.save(function(err) { if (err) { return res.json(500, { error: 'Cannot save the post' }); } post.populate('group', 'name').populate({ path: 'wallUser', select: 'name picture' }, function(err, doc) { res.json(doc); }); });
источник
Я подумал, что добавлю к этому, чтобы прояснить ситуацию для таких новичков, как я.
Что сильно сбивает с толку, если вы не будете осторожны, так это то, что есть три очень разных метода заполнения. Это методы разных объектов (Модель против Документа), они принимают разные входные данные и дают разные результаты (Документ против Обещания).
Вот они для тех, кто сбит с толку:
Document.prototype.populate ()
См. Полную документацию.
Этот работает с документами и возвращает документ. В исходном примере это выглядело бы так:
book.save(function(err, book) { book.populate('_creator', function(err, book) { // Do something }) });
Поскольку он работает с документами и возвращает документ, вы можете связать их вместе следующим образом:
book.save(function(err, book) { book .populate('_creator') .populate('/* Some other ObjectID field */', function(err, book) { // Do something }) });
Но не будь глупцом, как я, и попробуй сделать вот что:
book.save(function(err, book) { book .populate('_creator') .populate('/* Some other ObjectID field */') .then(function(book) { // Do something }) });
Помните: Document.prototype.populate () возвращает документ, так что это ерунда. Если вам нужно обещание, вам нужно ...
Document.prototype.execPopulate ()
См. Полную документацию.
Этот работает с документами, НО он возвращает обещание, которое разрешается в документе. Другими словами, вы можете использовать это так:
book.save(function(err, book) { book .populate('_creator') .populate('/* Some other ObjectID field */') .execPopulate() .then(function(book) { // Do something }) });
Так-то лучше. Наконец, есть ...
Model.populate ()
См. Полную документацию.
Этот работает на моделях и возвращает обещание. Поэтому он используется немного иначе:
book.save(function(err, book) { Book // Book not book .populate(book, { path: '_creator'}) .then(function(book) { // Do something }) });
Надеюсь, это помогло другим новичкам.
источник
К сожалению, это давняя проблема с мангустом, которая, я считаю, еще не решена:
https://github.com/LearnBoost/mongoose/issues/570
Что вы можете сделать, так это написать собственный пользовательский метод получения / установки (и установить для этого значение real
_customer
в отдельном свойстве). Например:var get_creator = function(val) { if (this.hasOwnProperty( "__creator" )) { return this.__creator; } return val; }; var set_creator = function(val) { this.__creator = val; return val; }; var bookSchema = new mongoose.Schema({ _creator: { type: mongoose.Schema.Types.ObjectId, ref: 'User', get: get_creator, set: set_creator }, description: String, });
ПРИМЕЧАНИЕ: я не тестировал его, и он может странно работать с
.populate
и при установке чистого идентификатора.источник
Мангуст 5.2.7
Это работает для меня (просто большая головная боль!)
exports.create = (req, res, next) => { const author = req.userData; const postInfo = new Post({ author, content: req.body.content, isDraft: req.body.isDraft, status: req.body.status, title: req.body.title }); postInfo.populate('author', '_id email role display_name').execPopulate(); postInfo.save() .then(post => { res.status(200).json(post); }).catch(error => { res.status(500).json(error); }); };
источник
Наверное, что-то. подобно
Book.createAsync(bookToSave).then((savedBook) => savedBook.populateAsync("creator"));
Это был бы самый приятный и наименее проблемный способ выполнить эту работу (с помощью обещаний Bluebird).
источник
закончили тем, что написали несколько функций Promise с возможностью карри, в которых вы заранее объявляете свою схему, функции query_adapter, data_adapter и заполняете строку. Для более короткой / простой реализации проще.
Вероятно, это не очень эффективно, но я подумал, что исполнение было довольно элегантным.
файл на github: curry_Promises.js
заявление
const update_or_insert_Item = mDB.update_or_insert({ schema : model.Item, fn_query_adapter : ({ no })=>{return { no }}, fn_update_adapter : SQL_to_MDB.item, populate : "headgroup" // fn_err : (e)=>{return e}, // fn_res : (o)=>{return o} })
казнь
Promise.all( items.map( update_or_insert_Item ) ) .catch( console.error ) .then( console.log )
источник