假设有一个表包含这样的文档:
{ _id: "aaaa", name: "One" }
{ _id: "bbbb", name: "Two" }
包含这样的文档的外表:
{ _id: "cccc", state: "pending", source_id: "aaaa" }
{ _id: "dddd", state: "finished", source_id: "aaaa" }
{ _id: "eeee", state: "finished", source_id: "aaaa" }
{ _id: "ffff", state: "pending", source_id: "aaaa" }
现在,我希望得到一个这样的数组:
[
{ _id: "aaaa", name: "One", pending: 2 },
{ _id: "bbbb", name: "Two", pending: 0 }
]
结果文件来自第一张表格。聚合使用状态为“待处理”的匹配(source_id = _id)外国文档的数量填充“pending”字段。
怎么会这样做?什么是正确的查询语法?
我尝试过的一个解决方案:使用$ lookup,$ match和$ sort来检索这样的结果:
{
_id: "aaaa",
name: "One",
foreign: [
{ _id: "cccc", state: "pending", source_id: "aaaa" },
{ _id: "ffff", state: "pending", source_id: "aaaa" }
]
},
{
_id: "bbbb",
name: "Two"
foreign: []
}
我能够在我的代码中获取子数组的长度,但是当外表有太多文档时,我最终得到“聚合超过最大文档大小”。因为结果超过16MB。
之前的帮助。但是我正在试图弄清楚如何过滤待处理的状态,正如原始问题所述:
db.apps.aggregate([
{
"$lookup": {
"from": "requests",
"localField": "_id",
"foreignField": "app_id",
"as": "foreign"
}
},
{
"$unwind": "$foreign"
},
{
$match: {
"foreign.state": 0
}
},
{
"$group": {
"_id": "$_id",
"name": {
"$first": "$name"
},
"pending": {
"$sum": 1
}
}
}
])
我得到了一些结果。但是,本地/第一个表中没有关联外国文档的文档(没有状态为0的外国文档)根本不会被返回。我希望仍然包含有0个待处理外国文档的行在结果中。
db.apps.aggregate([{
"$lookup": {
"from": "requests",
"as": "pending",
"let": {
"id": "$_id"
},
"pipeline": [{
"$match": {
"$expr": {
"$eq": ["$$id", "$app_id"]
}
}
},
{
"$match": {
"$expr": {
"$eq": [0, "$state"]
}
}
},
{
"$count": "count"
}
]
}
},
{
"$addFields": {
"pending": {
"$arrayElemAt": ["$pending.count", 0]
}
}
}
])
答案 0 :(得分:1)
您需要$unwind
并且基本上减少
db.localcollection.aggregate([
{ "$lookup": {
"from": "foreigncollection",
"localField": "_id",
"foreignField": "source_id",
"as": "foreign"
}},
{ "$unwind": "$foreign" },
{ "$group": {
"_id": "$_id",
"name": { "$first": "$name" },
"pending": { "$sum": 1 }
}}
])
或者使用MongoDB 3.6,使用富有表现力的$lookup
:
db.localcollection.aggregate([
{ "$lookup": {
"from": "foreigncollection",
"as": "pending",
"let": { "id": "$_id" },
"pipeline": [
{ "$match": { "$expr": { "$eq": [ "$$id", "$source_id" ] },
{ "$count": "count" }
]
}},
{ "$addFields": { "pending": { "$arrayElemAt": [ "$pending.count", 0 ] } } }
])
如果还有其他任何需要按标准“减少匹配”的话,则会在$match
之后直接$unwind
或在$match
内使用“管道“你有可能做到这一点。
任何一种形式都经过优化,可以在“返回”数组之前执行操作,甚至“不”返回数组以便不破坏BSON限制。关于管道优化和技术在Aggregate $lookup Total size of documents in matching pipeline exceeds maximum document size处发生的情况有一个更详细的解释,它通过示例显示甚至故意破坏该限制然后避免它。