mongodb - 使用 $lookup 运算符的多个连接条件

标签 mongodb join mongodb-query aggregation-framework

有以下两个集合:

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

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

我想在 user1user2 上加入这两个集合。

如何编写管道以获得这样的结果:

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

最佳答案

我们可以使用 $lookup 执行多个连接条件3.6 及更高版本中的聚合管道运算符。

我们需要使用 let 可选字段将字段的值分配给变量;然后,您可以在 pipeline 字段阶段访问这些变量,您可以在其中指定要在集合上运行的管道。

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

管道的最后一个阶段是 $replaceRoot聚合管道阶段,我们使用 $mergeObjects 简单地将 $lookup 结果与 $$ROOT 文档的一部分合并。运算符。

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"
                   }
                ]
             }
          }
       }
    ]
)

此管道产生如下所示的内容:

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

如果您使用的不是 3.6+ 版本,您可以先使用其中一个字段加入,比如说“user1”,然后从那里使用 $unwind 展开匹配文档的数组聚合管道运算符。管道的下一阶段是$redact使用 $$KEEP 过滤掉“已加入”集合中“user2”的值与输入文档不相等的文档的阶段和 $$PRUNE系统变量。然后您可以在 $project 中 reshape 您的文档。阶段。

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 ] }

关于mongodb - 使用 $lookup 运算符的多个连接条件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37086387/

相关文章:

MongoDB 对特定嵌套属性的投影

mongodb - 当配置实例使用与数据实例相同的二进制文件时升级 Mongodb

node.js - 查找和更新记录 - Mongoose

python - 保存引用字段 mongoengine

字段存在的MongoDB索引?

sql - Informix 到 HiveQL

mongodb - 比较同一文档的两个字段

php - CakePHP:如何更改此查找调用以包含关联表中不存在的所有记录?

R-合并两个数据框,但 ID 的值有分号

Mongodb 和聚合框架。对数组元素求和以对文档元素求和