我需要对一个mongodb集合进行聚合。但我找不到正确的聚合流水线。
事实上,我需要得到Ids的 不同文件 当 field1 == field2
(字段1与字段2不在同一文档中)。
例如我想查找所有的文档,当源文件与目标文件相同时。document1.fieldX == document2.fieldY
这是关于通过端口号查找目标服务器。
示例文档。
[
{
id: 444,
name: 'Server 1'
portSource: 1,
portTarget: 7,
},
{
id: 555,
name: 'Server 2'
portSource: 7,
portTarget: 1
},
{
id: 666,
name: 'Server 3'
portSource: 1,
portTarget: 8
},
{
id: 777,
name: 'Server 4'
portSource: 3,
portTarget: 5
},
{
id: 888,
name: 'Server 5'
portSource: 5,
portTarget: 3
},
]
希望的输出。
[
{
portSource: 1, portTarget: 7, sourceId : 444, targetId: 555
},
{
portSource: 3, portTarget: 5, sourceId : 777, targetId: 888
}
]
注1: 服务器: id: 666
不返回,因为有其他服务器与他的目标端口匹配。
注2: 正确的输出也可以是这样的。
(反向目标源)
[
{
portSource: 7, portTarget: 1, sourceId : 555, targetId: 444
},
{
portSource: 5, portTarget: 3, sourceId : 888, targetId: 777
}
]
或者它可以包含两次(正常方式和反向)。
[
{
portSource: 1, portTarget: 7, sourceId : 444, targetId: 555
},
{
portSource: 7, portTarget: 1, sourceId : 555, targetId: 444
},
{
portSource: 3, portTarget: 5, sourceId : 777, targetId: 888
},
{
portSource: 5, portTarget: 3, sourceId : 888, targetId: 777
}
]
你需要尝试 $lookup 在同一集合上的聚合管道阶段。
db.collectionName.aggregate([
{
$lookup: {
from: "collectionName", /** Same collection name */
let: { portSource: "$portSource" }, /** create a local variable 'portSource' from value of 'portSource' of current doc in lookup stage */
pipeline: [ /** pipline helps to execute aggregation stages */
{ $match: { $expr: { $and: [ { $eq: [ "$portTarget", "$$portSource" ] }, { $eq: [ "$portSource", "$$portTarget" ] } ] } } }, /** match to filter docs */
{ $project: { id: 1, _id: 0 } } /** project only `id` of matched doc in a new field `targetId` */
],
as: "targetId" /** will be an array, will be empty if none matches (In your case, mostly will be empty or array of single object) */
}
},
/** Only Pairs will have `targetId` non-empty, removing docs where `targetId` array is empty */
{ $match: { targetId: { $ne: [] } } },
/** create a new field `sourceId` from value of existing field `id`,
* re-create `targetId` from value of first elements `id` field in `targetId` array,
* You won't find this field for the doc where none of the docs matches for given `portSource` */
{
$addFields: { sourceId: "$id", targetId: { $arrayElemAt: [ "$targetId.id", 0 ] } }
},
/** Removing un-necessary field */
{
$project: { id: 0 }
}
])
测试。 mongoplayground