使用$ 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 }} ])