使用$ lookup操作符的多个连接条件

这是我的collections:

collection1:

{ user1: 1, user2: 2, percent: 0.56 } 

collection2:

 { user1: 1, user2: 2, percent: 0.3 } 

我想通过'user1'和'user2'来join这两个集合。

结果是这样的:

 { user1: 1, user2: 2, percent1: 0.56, percent2: 0.3 } 

我如何写pipe道?

我们可以使用版本3.6及更高版本的$lookup汇总pipe道运算符来执行多个连接条件。

我们需要使用let可选字段将字段的值赋给variables; 然后在pipeline字段阶段访问那些指定要在集合上运行的pipe道的variables。

请注意,在$match阶段,我们使用$expr评估查询运算符来比较字段的值。

stream水线的最后一个阶段是$replaceRoot聚合stream水线阶段,我们简单地使用$mergeObjects操作符将$lookup结果与部分$$ROOT文档$mergeObjects

 db.collection2.aggregate([ { $lookup: { from: "collection1", let: { firstUser: "$user1", secondUser: "$user2" }, pipeline: [ { $match: { $expr: { $and: [ { $eq: [ "$user1", "$$firstUser" ] }, { $eq: [ "$user2", "$$secondUser" ] } ] } } } ], as: "result" } }, { $replaceRoot: { newRoot: { $mergeObjects:[ { $arrayElemAt: [ "$result", 0 ] }, { percent1: "$$ROOT.percent1" } ] } } } ] ) 

这个pipe道产生的东西看起来像这样:

 { "_id" : ObjectId("59e1ad7d36f42d8960c06022"), "user1" : 1, "user2" : 2, "percent" : 0.3, "percent1" : 0.56 } 

如果你不是版本3.6+,你可以首先使用你的领域之一说“user1”然后从那里你解开使用$unwind聚合pipe道运算符的匹配文档的数组。 stream水线的下一个阶段是$redact阶段,您可以使用$$KEEP$$PRUNE系统variables过滤掉“joined”集合中的“user2”值与input文档不相等的文档。 然后,您可以在$project阶段重塑您的文档。

 db.collection1.aggregate([ { "$lookup": { "from": "collection2", "localField": "user1", "foreignField": "user1", "as": "collection2_doc" }}, { "$unwind": "$collection2_doc" }, { "$redact": { "$cond": [ { "$eq": [ "$user2", "$collection2_doc.user2" ] }, "$$KEEP", "$$PRUNE" ] }}, { "$project": { "user1": 1, "user2": 1, "percent1": "$percent", "percent2": "$collection2_doc.percent" }} ]) 

这产生:

 { "_id" : ObjectId("572daa87cc52a841bb292beb"), "user1" : 1, "user2" : 2, "percent1" : 0.56, "percent2" : 0.3 } 

如果集合中的文档具有相同的结构,并且经常发现自己正在执行此操作,则应考虑将这两个集合合并为一个集合,或者将这些集合中的文档插入到一个新集合中。

 db.collection3.insertMany( db.collection1.find({}, {"_id": 0}) .toArray() .concat(db.collection2.find({}, {"_id": 0}).toArray()) ) 

然后$group您的文件“user1”和“user2”

 db.collection3.aggregate([ { "$group": { "_id": { "user1": "$user1", "user2": "$user2" }, "percent": { "$push": "$percent" } }} ]) 

这产生:

 { "_id" : { "user1" : 1, "user2" : 2 }, "percent" : [ 0.56, 0.3 ] } 

您可以使用$ match$ projectpipe道来执行多个字段匹配。 (详细的答案见这里 – mongoDBjoin多个领域 )

 db.collection1.aggregate([ {"$lookup": { "from": "collection2", "localField": "user1", "foreignField": "user1", "as": "c2" }}, {"$unwind": "$c2"}, {"$project": { "user2Eq": {"$eq": ["$user2", "$c2.user2"]}, "user1": 1, "user2": 1, "percent1": "$percent", "percent2": "$c2.percent" }}, {"$match": { {"user2Eq": {"$eq": True}} }}, {"$project": { "user2Eq": 0 }} ])