我无法手动或自动填充新保存的对象上的创建者字段...我能找到的唯一方法是重新查询我已经拥有的对象,我不想这样做。
这是设置:
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?
});
});
编辑:最新的mongoose解决了这个问题并添加了填充功能,请参阅新接受的答案。
答案 0 :(得分:121)
您应该可以使用Model的填充函数来执行此操作:http://mongoosejs.com/docs/api.html#model_Model.populate在book的保存处理程序中,而不是:
book._creator = user;
你会做类似的事情:
Book.populate(book, {path:"_creator"}, function(err, book) { ... });
答案可能太迟了,但最近我被困在了这个问题上,这可能对其他人有用。
答案 1 :(得分:34)
如果有人还在寻找这个。
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 = book.toObject();
book._creator = user;
答案 2 :(得分:11)
只是详细说明并给出另一个例子,因为它帮助了我。这可能有助于那些想要在保存后检索部分填充对象的人。该方法也略有不同。花了一两个多小时寻找正确的方法。
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);
});
});
答案 3 :(得分:10)
使用文档#populate
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 => {
...
});
了解文档人口here。
答案 4 :(得分:8)
我的解决方案是使用execPopulate
,就像这样
const t = new MyModel(value)
return t.save().then(t => t.populate('my-path').execPopulate())
答案 5 :(得分:5)
我认为我想补充一下,以澄清像我这样的完全菜鸟的情况。
如果您不小心的话,将会造成极大的混乱,那就是存在三种非常不同的填充方法。它们是不同对象(模型与文档)的方法,采用不同的输入并给出不同的输出(文档与承诺)。
这里是为困惑的人准备的
此文档适用于文档并返回文档。在原始示例中,它看起来像这样:
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()返回一个文档,所以这是无稽之谈。如果您想要一个承诺,则需要...
这对文档起作用,但是它返回一个可解决该文档的承诺。 换句话说,您可以像这样使用它:
book.save(function(err, book) {
book
.populate('_creator')
.populate('/* Some other ObjectID field */')
.execPopulate()
.then(function(book) {
// Do something
})
});
那更好。最后,有...
这个在模型上工作并返回承诺。因此,它的用法有所不同:
book.save(function(err, book) {
Book // Book not book
.populate(book, { path: '_creator'})
.then(function(book) {
// Do something
})
});
希望对其他一些新来者有所帮助。
答案 6 :(得分:1)
不幸的是,这是一个长期存在的猫鼬问题,我认为还没有解决:
https://github.com/LearnBoost/mongoose/issues/570
您可以做的是为自己编写自己的自定义getter / setter(并在单独的属性中设置 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
奇怪地设置并且在设置纯ID时。
答案 7 :(得分:1)
猫鼬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);
});
};
答案 8 :(得分:0)
可能是某事。像
Book.createAsync(bookToSave).then((savedBook) => savedBook.populateAsync("creator"));
使这项工作成为最好和最不成问题的方法(使用Bluebird承诺)。
答案 9 :(得分:0)
最后编写了一些可咖喱的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 )
答案 10 :(得分:0)
在模型中保存文档然后填充
chatRoom = await chatRoom.save();
const data = await chatRoom
.populate("customer", "email dp")
.populate({
path: "admin",
select: "name logo",
})
.execPopulate();
答案 11 :(得分:0)
我不会在这里添加任何新内容。
这只是使用 async/await 的一种更简洁的编写方式:
const newCourse = new Course(new_course_data);
const populate_options = [
// Here write your populate options
];
const created_course = await newCourse.save();
await created_course.populate(populate_options).execPopulate();