MongoDB $lookup https://docs.mongodb.com/manual/reference/operator/aggregation/lookup/不会使用“查找”集合中的匹配项“更新”现有数组中的元素。它会only输出与给定条件匹配的“数组”,与您拥有的值的“现有数组”或奇异值相匹配。
为了将条目与“服务器”“结婚”$lookup https://docs.mongodb.com/manual/reference/operator/aggregation/lookup/操作,您必须继续执行以下选项之一才能以您想要的形式返回。
$首先展开数组
最简单的形式是简单地更改文档的结构,以便源中的每个数组成员都是它的首先自己的文档,在您真正尝试“结合”相关信息之前:
db.studijneProgramy.aggregate([
{ "$unwind": "$garranti" },
{ "$lookup": {
"from": "osoby",
"as": "garranti.garrant",
"localField": "garranti.id",
"foreignField": "_id"
}},
{ "$unwind": "$garranti.garrant" },
{ "$group": {
"_id": "$_id",
"garranti": { "$push": "$garranti" }
}}
])
由于原始数组材料现在是单个文档,因此每个文档仅接收来自连接集合的匹配“数组”。这个会$unwind https://docs.mongodb.com/manual/reference/operator/aggregation/unwind/再次使用$group https://docs.mongodb.com/manual/reference/operator/aggregation/group/为了$push https://docs.mongodb.com/manual/reference/operator/aggregation/push/到带有“连接”条目的最终数组形式。
关联“数组”
在支持它的版本中有点花哨的是使用以下功能$indexOfArray https://docs.mongodb.com/manual/reference/operator/aggregation/indexOfArray/ and $arrayElemAt https://docs.mongodb.com/manual/reference/operator/aggregation/indexOfArray/为了“匹配”输出数组$lookup https://docs.mongodb.com/manual/reference/operator/aggregation/lookup/到文档中现有的数组条目:
db.studijneProgramy.aggregate([
{ "$lookup": {
"from": "osoby",
"as": "related",
"localField": "garranti.id",
"foreignField": "_id"
}},
{ "$project": {
"garranti": {
"$map": {
"input": "$garranti",
"in": {
"typ": "$$this.typ",
"id": "$$this.id",
"garrant": {
"$arrayElemAt": [
"$related",
{ "$indexOfArray": [ "$related._id", "$$this.id" ] }
]
}
}
}
}
}}
])
因此查找返回“匹配数组”(related
)然后您“查找”这些匹配的条目并将它们转置到原始文档数组中$map https://docs.mongodb.com/manual/reference/operator/aggregation/map/。当然这需要额外的$project https://docs.mongodb.com/manual/reference/operator/aggregation/project/stage 或类似的内容,以便重塑文档结果,因为您无法“定位”现有数组的每个元素$lookup https://docs.mongodb.com/manual/reference/operator/aggregation/lookup/输出如前所述。
这实际上是“服务器”上某些库(例如“mongoose”)为“客户端上的连接模拟”所做的直接关联。实际上,“外部”条目被“映射”到现有数组上。
子管道处理
有点花哨和冗长的是使用“子管道”处理的另一种选择不相关子查询 https://docs.mongodb.com/manual/reference/operator/aggregation/lookup/#uncorrelated-subquery从 MongoDB 3.6 及以上版本可用。这里我们基本上是在“子管道”中进行操作$lookup https://docs.mongodb.com/manual/reference/operator/aggregation/lookup/而不是在后续聚合阶段进行处理:
db.studijneProgramy.aggregate([
{ "$lookup": {
"from": "osoby",
"as": "garranti",
"let": { "garranti": "$garranti" },
"pipeline": [
{ "$match": {
"$expr": { "$in": [ "$_id", "$$garranti.id" ] }
}},
{ "$addFields": {
"docs": {
"$filter": {
"input": "$$garranti",
"cond": {
"$eq": [ "$$this.id", "$_id" ]
}
}
}
}},
{ "$unwind": "$docs" },
{ "$replaceRoot": {
"newRoot": {
"$mergeObjects": [
"$docs",
{ "garrant": {
"$arrayToObject": {
"$filter": {
"input": { "$objectToArray": "$$ROOT" },
"cond": { "$ne": [ "$$this.k", "docs"] }
}
}
}}
]
}
}}
]
}}
])
这种方式将操作“彻底”转变,并有效地将“源文档”中的“匹配数组元素”作为数组放入每个匹配的外部元素中。
然后处理有效地使用$unwind https://docs.mongodb.com/manual/reference/operator/aggregation/lookup/在过滤后的源列表上,然后合并外部集合中的内容,因此现在看来$lookup https://docs.mongodb.com/manual/reference/operator/aggregation/lookup/“输出数组”实际上是来自“本地数组”的数据,现在与“外部内容”“合并”。
实际上,这只是对相同内容的更奇特的调用$map https://docs.mongodb.com/manual/reference/operator/aggregation/map/上面的过程,但是对条目进行“关联”before结果与原始父文档合并,覆盖原始数组属性。
我认为某个地方有一个 JIRA 可以解决这个问题,但我有一种感觉“按设计工作”所有此类报告均已标记,因此不太可能改变目前的做法。
因此,您的误解是“连接”会“自动”与数组条目“合并”。它不是。
如果您实际上想“合并数组输出”,那么上面的方法就是“服务器”方法。