【发布时间】:2017-05-25 17:21:25
【问题描述】:
TLDR
如何使用 MongoDB 聚合来包含另一个集合中的相关文档,该集合通过一对多关系链接?
本质上,我想做的是能够获取问题列表并包含与该问题相关的所有标志。
更新(2016 年 11 月 7 日):使用下面发布的解决方案解决。
更新(2016 年 5 月 7 日):通过使用 $unwind, $lookup, $project 等的组合,我在某种程度上设法获得了带有相关标志的问题列表。更新后的查询如下。
问题 (05/07/2016): 我只能获取具有嵌套标志的问题。我想获取 所有 个问题,即使它们没有任何标志。
我有两个集合,一个用于内容,一个用于内容标志,如下:
内容的架构(问题集合)
{
"_id" : ObjectId("..."),
"slug" : "a-sample-title",
"content" : "Some content.",
"title" : "A Sample Title.",
"kind" : "Question",
"updated" : ISODate("2016-06-08T08:54:26.104Z"),
"isPublished" : true,
"isFeatured" : false,
"flags" : [
ObjectId("<id_of_flag_one>"),
ObjectId("<id_of_flag_two>")
],
"answers" : [
ObjectId("..."),
ObjectId("...")
],
"related" : [],
"isAnswered" : true,
"__v" : 4
}
标志的 shcema(标志集合)
{
"_id" : ObjectId("..."),
"flaggedBy" : ObjectId("<a_users_id>"),
"type" : "like",
"__v" : 0
}
在上面,一个问题可以有多个标志,一个标志只能有一个问题。我想要做的是在查询问题集合时返回问题的所有标志。我曾尝试使用聚合来做到这一点,但运气不错。
这是我正在使用的更新查询(05/07/2016)
fetchQuestions: (permission, params) => {
return new Promise((resolve, reject) => {
let query = Question.aggregate([
{
$lookup: {
from: 'users',
localField: 'author',
foreignField: '_id',
as: 'authorObject'
}
},
{
$unwind: '$authorObject'
},
{
$unwind: '$flags'
},
{
$lookup: {
from: 'flags',
localField: 'flags',
foreignField: '_id',
as: 'flagObjects'
}
},
{
$unwind: '$flagObjects'
},
{
$group: {
_id: {
_id: '$_id',
title: '$title',
content: '$content',
updated: '$updated',
isPublished: '$isPublished',
isFeatured: '$isFeatured',
isAnswered: '$isAnswered',
answers: '$answers',
author: '$authorObject'
},
flags: {
$push: '$flags'
},
flagObjects: {
$push: '$flagObjects'
}
}
},
{
$project: {
_id: 0,
_id: '$_id._id',
title: '$_id.title',
content: '$_id.content',
updated: '$_id.updated',
isPublished: '$_id.isPublished',
isFeatured: '$_id.isFeatured',
author: {
fullname: '$_id.author.fullname',
username: '$_id.author.username'
},
flagCount: {
$size: '$flagObjects'
},
answersCount: {
$size: '$_id.answers'
},
flags: '$flagObjects',
wasFlagged: {
$cond: {
if: {
$gt: [
{
$size: '$flagObjects'
},
0
]
},
then: true,
else: false
}
}
}
},
{
$sort: {
updated: 1
}
},
{
$skip: 0
},
// {
// $limit: 110
// }
])
.exec((error, result) => {
if(error) reject(error);
else resolve(result);
});
});
},
我曾尝试使用其他聚合运算符,例如 $unwind 和 $group,但结果集包含五个或更少的项目,我发现很难掌握这些应该如何协同工作以得到我的概念我需要什么。
这是我得到的回应,这正是我所需要的。唯一的问题是,如上所述,我只收到带有标记的问题,而不是所有问题。
"questions": [
{
"_id": "5757dd42d0c2ae292f76f11a",
"flags": [
{
"_id": "5774e0a81f2874821f71ace8",
"flaggedBy": "57569d02d0c2ae292f76f0f5",
"type": "concern",
"__v": 0
},
{
"_id": "577a0f5414b834372a6ac772",
"flaggedBy": "5756aa79d0c2ae292f76f0f8",
"type": "concern",
"__v": 0
}
],
"title": "A question for the landing page.",
"content": "This is a question that will appear on the landing page.",
"updated": "2016-06-08T08:54:26.104Z",
"isPublished": true,
"isFeatured": false,
"author": {
"fullname": "Matt Finucane",
"username": "matfin-386829"
},
"flagCount": 2,
"answersCount": 2,
"wasFlagged": true
},
...,
...,
...
]
【问题讨论】:
-
如果您的 MongoDB 版本是 3.2 或更高版本,那么
$lookup -
嗯,我不明白。我在聚合查询中使用 $lookup。
-
我还可以确认我使用的是 MongoDB 版本 3.2.x
-
为什么你有两个
$lookup舞台?删除第一个$lookup阶段。还有$lookupdoes not play well with array field in 3.2. -
第一个 $lookup 用于获取问题的作者,以便稍后在我的投影中使用它。据我了解,这类似于在 Mongoose 中使用 populate() 函数。我使用您发布的链接中的建议修改了聚合查询,现在我返回了一个包含 5 个标志对象的列表。我的问题预测现在被忽略了。如何编写此代码,以便在查询的结果集中嵌套 flagObjects,而不更改查询的输出。使用聚合时我走的是正确的道路吗?
标签: mongodb mongodb-query aggregation-framework