Javascript 存在引用时不调用Mongoose模型填充回调
我试图使用Mongoose的Model.populate()将用户ID转换为用户,该用户ID位于通过聚合和展开获取的文档的子结构中。我猜可能是我的模式出了问题,或者可能是解压中断了与子模式的连接 问题是:当存在有效引用时,不会调用填充回调函数。当没有子结构时,调用回调,原始文档保持不变 结构: 我有一些文章,每个用户可以没有或有很多文章评级 我在ArticleRating中使用了两个参考,与文章和进行评级的用户相关 过程: 这个过程实际上是将文章导出为(传统的)CSV格式,并将结构扁平化为具有用户特定评级的重复文章行。“展开”非常适合此操作,而“保留空值”将保留没有分级的项目 调试: 我尝试深入了解Model.populate代码。所有的承诺和回调包装都非常复杂,但是我可以看到底层的填充调用也没有调用内部回调。我没有使用promise变体,但不能100%确定是否应该使用?(Mongoose文档在回调和承诺之间的用例上有点模糊) 我已经仔细检查了我的模式,尝试将模型显式地添加到populate调用中(这不应该是必需的,因为它在模式中)。没有错误或异常,它不会崩溃 在Chrome调试器中单步执行代码显示的模型与我预期的一样:前几篇文章有一个带有有效ObjectId的rating.userId,但在这些情况下,不会调用populate回调函数。接下来的一百篇文章没有“评级”集,所有文章都会可靠地调用回调 所以我猜我做错了什么,是把Model.populate引入了一个错误不正常的路径 注意:我知道我可以重写代码以使用聚合$lookup或其他嵌入结构,而不是外部引用,但我已经完成了功能拼图的最后一部分,希望它能够正常工作 这是简化的模式:Javascript 存在引用时不调用Mongoose模型填充回调,javascript,node.js,mongodb,mongodb-query,aggregation-framework,Javascript,Node.js,Mongodb,Mongodb Query,Aggregation Framework,我试图使用Mongoose的Model.populate()将用户ID转换为用户,该用户ID位于通过聚合和展开获取的文档的子结构中。我猜可能是我的模式出了问题,或者可能是解压中断了与子模式的连接 问题是:当存在有效引用时,不会调用填充回调函数。当没有子结构时,调用回调,原始文档保持不变 结构: 我有一些文章,每个用户可以没有或有很多文章评级 我在ArticleRating中使用了两个参考,与文章和进行评级的用户相关 过程: 这个过程实际上是将文章导出为(传统的)CSV格式,并将结构扁平化为具有用
const ArticleRatingSchema = new Schema({
articleId: {type: Schema.Types.ObjectId, ref:'Article'},
userId: {type: Schema.Types.ObjectId, ref:'User'},
rating: String,
comment: String,
});
const ArticleSchema = new Schema({
title: String,
rating: ArticleRatingSchema,
});
这就是查找
// Find all articles relating to this project, and their ratings.
// Unwind does the duplicate per-user, and preserve keeps un-rated articles.
articleModel.aggregate([
{$match: {projectId: projectId}},
{$lookup:{from:'articleratings', localField:'_id', foreignField:'articleId', as:'rating' }},
{$unwind: {path:'$rating', preserveNullAndEmptyArrays:true}}
], (err, models) =>
{
if (!err) {
models.map((article) => {
articleModel.populate(article, {path:'rating.userId', model:'User'}, (err, article)=> {
// Process the article...
// this callback only gets called where there is NO rating in the article.
});
});
}
我意识到这是因为我在同步map()循环中处理集合,这两种情况必须有所不同,因为不匹配的填充是同步回调,而匹配的替换稍后回调 如果在回调中输入console.log(),我会发现这四个匹配的案例是在CSV格式化和下载之后最后处理的 所以答案是:正在调用populate,但是是异步的
我需要重新设计map()循环,以适应通常的异步模式。我个人对您认为要在聚合管道中使用什么,然后需要
.populate()
结果感到有点困惑。因为要求使用.populate()
本质上意味着向服务器发出额外的查询以“模拟连接”
因此,既然实际上是“在服务器上加入”,那么您真的应该使用它
您可以使用.populate()
,我将展示一些代码,以表明它可以完成。但这确实是多余的,因为您也可以在服务器上完成所有工作
因此,我对结构的最佳“近似”是:
文章
{
"_id" : ObjectId("5962104312246235cdcceb16"),
"title" : "New News",
"ratings" : [ ],
"__v" : 0
}
{
"_id" : ObjectId("5962104312246235cdcceb17"),
"articleId" : ObjectId("5962104312246235cdcceb16"),
"userId" : ObjectId("5962104312246235cdcceb13"),
"rating" : "5",
"comment" : "Great!",
"__v" : 0
}
{
"_id" : ObjectId("5962104312246235cdcceb18"),
"articleId" : ObjectId("5962104312246235cdcceb16"),
"userId" : ObjectId("5962104312246235cdcceb14"),
"rating" : "3",
"comment" : "Okay I guess ;)",
"__v" : 0
}
{
"_id" : ObjectId("5962104312246235cdcceb19"),
"articleId" : ObjectId("5962104312246235cdcceb16"),
"userId" : ObjectId("5962104312246235cdcceb15"),
"rating" : "1",
"comment" : "Hated it :<",
"__v" : 0
}
{
"_id" : ObjectId("5962104312246235cdcceb13"),
"name" : "Bill",
"email" : "bill@example.com",
"__v" : 0
}
{
"_id" : ObjectId("5962104312246235cdcceb14"),
"name" : "Fred",
"email" : "fred@example.com",
"__v" : 0
}
{
"_id" : ObjectId("5962104312246235cdcceb15"),
"name" : "Ted",
"email" : "ted@example.com",
"__v" : 0
}
文章评级
{
"_id" : ObjectId("5962104312246235cdcceb16"),
"title" : "New News",
"ratings" : [ ],
"__v" : 0
}
{
"_id" : ObjectId("5962104312246235cdcceb17"),
"articleId" : ObjectId("5962104312246235cdcceb16"),
"userId" : ObjectId("5962104312246235cdcceb13"),
"rating" : "5",
"comment" : "Great!",
"__v" : 0
}
{
"_id" : ObjectId("5962104312246235cdcceb18"),
"articleId" : ObjectId("5962104312246235cdcceb16"),
"userId" : ObjectId("5962104312246235cdcceb14"),
"rating" : "3",
"comment" : "Okay I guess ;)",
"__v" : 0
}
{
"_id" : ObjectId("5962104312246235cdcceb19"),
"articleId" : ObjectId("5962104312246235cdcceb16"),
"userId" : ObjectId("5962104312246235cdcceb15"),
"rating" : "1",
"comment" : "Hated it :<",
"__v" : 0
}
{
"_id" : ObjectId("5962104312246235cdcceb13"),
"name" : "Bill",
"email" : "bill@example.com",
"__v" : 0
}
{
"_id" : ObjectId("5962104312246235cdcceb14"),
"name" : "Fred",
"email" : "fred@example.com",
"__v" : 0
}
{
"_id" : ObjectId("5962104312246235cdcceb15"),
"name" : "Ted",
"email" : "ted@example.com",
"__v" : 0
}
然后是聚合语句:
Article.aggregate(
[
{ "$lookup": {
"from": ArticleRating.collection.name,
"localField": "_id",
"foreignField": "articleId",
"as": "ratings"
}},
{ "$unwind": "$ratings" },
{ "$lookup": {
"from": User.collection.name,
"localField": "ratings.userId",
"foreignField": "_id",
"as": "ratings.userId",
}},
{ "$unwind": "$ratings.userId" },
{ "$group": {
"_id": "$_id",
"title": { "$first": "$title" },
"ratings": { "$push": "$ratings" }
}}
],
(err,articles) => {
if (err) callback(err);
log(articles);
callback();
}
)
结果是:
{
"_id": "5962126f3ef2fb35efeefd94",
"title": "New News",
"ratings": [
{
"_id": "5962126f3ef2fb35efeefd95",
"articleId": "5962126f3ef2fb35efeefd94",
"userId": {
"_id": "5962126f3ef2fb35efeefd91",
"name": "Bill",
"email": "bill@example.com",
"__v": 0
},
"rating": "5",
"comment": "Great!",
"__v": 0
},
{
"_id": "5962126f3ef2fb35efeefd96",
"articleId": "5962126f3ef2fb35efeefd94",
"userId": {
"_id": "5962126f3ef2fb35efeefd92",
"name": "Fred",
"email": "fred@example.com",
"__v": 0
},
"rating": "3",
"comment": "Okay I guess ;)",
"__v": 0
},
{
"_id": "5962126f3ef2fb35efeefd97",
"articleId": "5962126f3ef2fb35efeefd94",
"userId": {
"_id": "5962126f3ef2fb35efeefd93",
"name": "Ted",
"email": "ted@example.com",
"__v": 0
},
"rating": "1",
"comment": "Hated it :<",
"__v": 0
}
]
}
全输出
Mongoose: users.remove({}, {})
Mongoose: articles.remove({}, {})
Mongoose: articleratings.remove({}, {})
Mongoose: users.insert({ name: 'Bill', email: 'bill@example.com', _id: ObjectId("596219ff6f73ed36d868ed40"), __v: 0 })
Mongoose: users.insert({ name: 'Fred', email: 'fred@example.com', _id: ObjectId("596219ff6f73ed36d868ed41"), __v: 0 })
Mongoose: users.insert({ name: 'Ted', email: 'ted@example.com', _id: ObjectId("596219ff6f73ed36d868ed42"), __v: 0 })
Mongoose: articles.insert({ title: 'New News', _id: ObjectId("596219ff6f73ed36d868ed43"), ratings: [], __v: 0 })
Mongoose: articleratings.insert({ articleId: ObjectId("596219ff6f73ed36d868ed43"), userId: ObjectId("596219ff6f73ed36d868ed40"), rating: '5', comment: 'Great!', _id: ObjectId("596219ff6f73ed36d868ed44"), __v: 0 })
Mongoose: articleratings.insert({ articleId: ObjectId("596219ff6f73ed36d868ed43"), userId: ObjectId("596219ff6f73ed36d868ed41"), rating: '3', comment: 'Okay I guess ;)', _id: ObjectId("596219ff6f73ed36d868ed45"), __v: 0 })
Mongoose: articleratings.insert({ articleId: ObjectId("596219ff6f73ed36d868ed43"), userId: ObjectId("596219ff6f73ed36d868ed42"), rating: '1', comment: 'Hated it :<', _id: ObjectId("596219ff6f73ed36d868ed46"), __v: 0 })
Mongoose: articles.aggregate([ { '$lookup': { from: 'articleratings', localField: '_id', foreignField: 'articleId', as: 'ratings' } } ], {})
Mongoose: users.find({ _id: { '$in': [ ObjectId("596219ff6f73ed36d868ed40") ] } }, { fields: {} })
Mongoose: users.find({ _id: { '$in': [ ObjectId("596219ff6f73ed36d868ed41") ] } }, { fields: {} })
Mongoose: users.find({ _id: { '$in': [ ObjectId("596219ff6f73ed36d868ed42") ] } }, { fields: {} })
[
{
"_id": "596219ff6f73ed36d868ed43",
"title": "New News",
"__v": 0,
"ratings": [
{
"_id": "596219ff6f73ed36d868ed44",
"articleId": "596219ff6f73ed36d868ed43",
"userId": {
"_id": "596219ff6f73ed36d868ed40",
"name": "Bill",
"email": "bill@example.com",
"__v": 0
},
"rating": "5",
"comment": "Great!",
"__v": 0
},
{
"_id": "596219ff6f73ed36d868ed45",
"articleId": "596219ff6f73ed36d868ed43",
"userId": {
"_id": "596219ff6f73ed36d868ed41",
"name": "Fred",
"email": "fred@example.com",
"__v": 0
},
"rating": "3",
"comment": "Okay I guess ;)",
"__v": 0
},
{
"_id": "596219ff6f73ed36d868ed46",
"articleId": "596219ff6f73ed36d868ed43",
"userId": {
"_id": "596219ff6f73ed36d868ed42",
"name": "Ted",
"email": "ted@example.com",
"__v": 0
},
"rating": "1",
"comment": "Hated it :<",
"__v": 0
}
]
}
]
Mongoose: articles.aggregate([ { '$lookup': { from: 'articleratings', localField: '_id', foreignField: 'articleId', as: 'ratings' } } ], {})
Mongoose: users.find({ _id: { '$in': [ ObjectId("596219ff6f73ed36d868ed40") ] } }, { fields: {} })
Mongoose: users.find({ _id: { '$in': [ ObjectId("596219ff6f73ed36d868ed41") ] } }, { fields: {} })
Mongoose: users.find({ _id: { '$in': [ ObjectId("596219ff6f73ed36d868ed42") ] } }, { fields: {} })
[
{
"_id": "596219ff6f73ed36d868ed43",
"title": "New News",
"__v": 0,
"ratings": [
{
"_id": "596219ff6f73ed36d868ed44",
"articleId": "596219ff6f73ed36d868ed43",
"userId": {
"_id": "596219ff6f73ed36d868ed40",
"name": "Bill",
"email": "bill@example.com",
"__v": 0
},
"rating": "5",
"comment": "Great!",
"__v": 0
},
{
"_id": "596219ff6f73ed36d868ed45",
"articleId": "596219ff6f73ed36d868ed43",
"userId": {
"_id": "596219ff6f73ed36d868ed41",
"name": "Fred",
"email": "fred@example.com",
"__v": 0
},
"rating": "3",
"comment": "Okay I guess ;)",
"__v": 0
},
{
"_id": "596219ff6f73ed36d868ed46",
"articleId": "596219ff6f73ed36d868ed43",
"userId": {
"_id": "596219ff6f73ed36d868ed42",
"name": "Ted",
"email": "ted@example.com",
"__v": 0
},
"rating": "1",
"comment": "Hated it :<",
"__v": 0
}
]
}
]
Mongoose: articles.aggregate([ { '$lookup': { from: 'articleratings', localField: '_id', foreignField: 'articleId', as: 'ratings' } }, { '$unwind': '$ratings' }, { '$lookup': { from: 'users', localField: 'ratings.userId', foreignField: '_id', as: 'ratings.userId' } }, { '$unwind': '$ratings.userId' }, { '$group': { _id: '$_id', title: { '$first': '$title' }, ratings: { '$push': '$ratings' } } } ], {})
[
{
"_id": "596219ff6f73ed36d868ed43",
"title": "New News",
"ratings": [
{
"_id": "596219ff6f73ed36d868ed44",
"articleId": "596219ff6f73ed36d868ed43",
"userId": {
"_id": "596219ff6f73ed36d868ed40",
"name": "Bill",
"email": "bill@example.com",
"__v": 0
},
"rating": "5",
"comment": "Great!",
"__v": 0
},
{
"_id": "596219ff6f73ed36d868ed45",
"articleId": "596219ff6f73ed36d868ed43",
"userId": {
"_id": "596219ff6f73ed36d868ed41",
"name": "Fred",
"email": "fred@example.com",
"__v": 0
},
"rating": "3",
"comment": "Okay I guess ;)",
"__v": 0
},
{
"_id": "596219ff6f73ed36d868ed46",
"articleId": "596219ff6f73ed36d868ed43",
"userId": {
"_id": "596219ff6f73ed36d868ed42",
"name": "Ted",
"email": "ted@example.com",
"__v": 0
},
"rating": "1",
"comment": "Hated it :<",
"__v": 0
}
]
}
]
Mongoose:users.remove({},{})
Mongoose:articles.remove({},{})
Mongoose:articleratings.remove({},{})
Mongoose:users.insert({name:'Bill',email:'bill@example.com“,”id:ObjectId(“596219ff6f73ed36d868ed40”),”v:0})
Mongoose:users.insert({name:'Fred',email:'fred@example.com“,”id:ObjectId(“596219ff6f73ed36d868ed41”),”v:0})
Mongoose:users.insert({name:'Ted',email:'ted@example.com“,”id:ObjectId(“596219ff6f73ed36d868ed42”),”v:0})
Mongoose:articles.insert({标题:'新新闻',_id:ObjectId(“596219ff6f73ed36d868ed43”),评级:[],_v:0})
Mongoose:articleratings.insert({articleId:ObjectId(“596219ff6f73ed36d868ed43”)、userId:ObjectId(“596219ff6f73ed36d868ed40”)、rating:'5',comment:'Great!'、id:ObjectId(“596219ff6f73ed36d868ed44”)、\uu v:0})
Mongoose:articleratings.insert({articleId:ObjectId(“596219ff6f73ed36d868ed43”)、userId:ObjectId(“596219ff6f73ed36d868ed41”)、rating:'3',comment:'Okay I guess;),(id:ObjectId(“596219ff6f73ed36d868ed45”),u v:0})
Mongoose:articleratings.insert({articleId:ObjectId(“596219ff6f73ed36d868ed43”)、userId:ObjectId(“596219ff6f73ed36d868ed42”)、评级:“1”、注释:“它: