我有一个 hero
集合,其中每个 hero 文档如下所示:
{
_id:'the-name-of-the-hero',
name: 'Name of Hero',
(...), //other properties to this hero
relations: [
{
hero: 'the-id-of-another-hero',
relationType: 'trust'
},
{
hero: 'yet-another-id-of-another-hero',
relationType: 'hate'
}
]
}
relations.hero
指向另一个英雄的 _id
。我需要获取更多相关英雄的信息,因此我使用聚合 $lookup
将每个英雄与“英雄”集合进行匹配,以获取它的 name
(和其他数据,但针对问题简化了项目)。这里是当前工作的查询,记录在案:
let aggregate = db.collection('hero').aggregate([
// grabbing an specific hero
{ $match: { _id } },
//populate relations
{
$lookup: {
from: 'hero',
let: { letId: '$relations.hero' }, //create a local variable for the pipeline to use
// localField: "relations.hero", //this would bring entire hero data, which is unnecessary
// foreignField: "_id", //this would bring entire hero data, which is unnecessary
pipeline: [
//match each $relations.hero (as "$$letId") in collection hero's (as "from") $_id
{ $match: { $expr: { $in: ['$_id', '$$letId'] } } },
//grab only the _id and name of the matched heroes
{ $project: { name: 1, _id: 1 } },
//sort by name
{ $sort:{ name: 1 } }
],
//replace the current relations with the new relations
as: 'relations',
},
}
]).toArray(someCallbackHere);
简而言之,$lookup
在 hero
集合上使用 pipeline
匹配每个 relations.hero
和只带回 _id
和 name
(在 UI 上打印真实姓名)并用这个新的 替换当前的
,生成文档为:relations
关系
{
_id:'the-name-of-the-hero',
name: 'Name of Hero',
(...), //other properties to this hero
relations: [
{
_id: 'the-id-of-another-hero',
name: 'The Real Name of Another Hero',
},
{
_id: 'yet-another-id-of-another-hero',
name: 'Yet Another Real Name of Another Hero',
}
]
}
问题:
我可以在管道上添加什么以使其将匹配的英雄与原始 relations
合并,以便不仅具有投影的 _id
和 name
,还有原来的relationType
?即有如下结果:
{
_id:'the-name-of-the-hero',
name: 'Name of Hero',
(...), //other properties to this hero
relations: [
{
_id: 'the-id-of-another-hero',
name: 'The Real Name of Another Hero',
relationType: 'trust' //<= kept from the original relations
},
{
_id: 'yet-another-id-of-another-hero',
name: 'Yet Another Real Name of Another Hero',
relationType: 'hate' //<= kept from the original relations
}
]
}
我尝试将 导出为:'relationsFull'
,然后尝试将 $push
与 $mergeObjects
作为聚合下一步的一部分但没有运气。我尝试做与管道步骤相同的操作(而不是新的聚合步骤),但总是以 relations
为空数组结束..
我将如何编写一个新的聚合步骤来将旧的 relations
对象与新查找的 relations
对象合并?
注意:考虑 MongoDB 3.6 或更高版本(即,不需要 $unwind
数组,至少对于 $lookup
).如果该信息很重要,我正在使用 Node.js 驱动程序进行查询。
最佳答案
您可以使用以下聚合
db.collection("hero").aggregate([
{ "$match": { _id } },
{ "$unwind": "$relations" },
{ "$lookup": {
"from": "hero",
"let": { "letId": "$relations.hero" },
"pipeline": [
{ "$match": { "$expr": { "$eq": ["$_id", "$$letId"] } } },
{ "$project": { "name": 1 } }
],
"as": "relation"
}},
{ "$unwind": "$relation" },
{ "$addFields": { "relations.name": "$relation.name" }},
{ "$group": {
"_id": "$_id",
"relations": { "$push": "$relations" },
"name": { "$first": "$name" },
"rarity": { "$first": "$rarity" },
"classType": { "$first": "$classType" }
}}
])
或者你也可以使用它
db.collection("hero").aggregate([
{ "$match": { _id } },
{ "$lookup": {
"from": "hero",
"let": { "letId": "$relations.hero" },
"pipeline": [
{ "$match": { "$expr": { "$in": ["$_id", "$$letId"] } } },
{ "$project": { "name": 1 } }
],
"as": "lookupRelations"
}},
{ "$addFields": {
"relations": {
"$map": {
"input": "$relations",
"as": "rel",
"in": {
"$mergeObjects": [
"$$rel",
{ "name": { "$arrayElemAt": ["$lookupRelations.name", { "$indexOfArray": ["$lookupRelations._id", "$$rel._id"] }] }}
]
}
}
}
}}
])
关于mongodb - 在 $lookup 之后将原始对象数组合并到 "as"字段中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54832677/