拥有以下两个系列:

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

推荐答案

在3.6版及更高版本中,我们可以使用$lookup聚合管道操作符执行多个连接条件.

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

请注意,在$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聚合管道操作符从那里释放匹配文档的array.管道中的下一个阶段是$redact阶段,在该阶段中,使用$$KEEP$$PRUNE系统变量过滤掉"joined"集合中的"user2"值与输入文档不相等的文档.然后,您可以在$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
}

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

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

然后按"user1"和"user2"输入$group个文档

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

由此产生:

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

Mongodb相关问答推荐

在MondoDB中:将对象数组从切片索引数组切片,并通过聚合推入数组

带dropTarget的MongoDB renameCollection命令是原子的吗

MongoDB 对特定搜索查询的响应时间较长

Mongodb Timeseries / Golang - ['timestamp' 必须存在并包含有效的 BSON UTC 日期时间值]

在mongoose 中按键查找嵌套对象

MongoDB聚合 - 用另一个数组过滤数组

为什么使用整数作为 pymongo 的键不起作用?

连接到远程 mongo 服务器导致异常连接失败

如何使用 mongoose 从 MongoDb 获取数据?

Golang/mgo:如何让 MongoDB 在字段中使用当前时间?

MongoDB $或PHP中的查询

不能在模块外使用 import 语句

如何使用 mongodb 和 php 正确处理分页查询?

在 URL 中使用 ID(来自 mongo 的 ObjectId)是否安全?

适用于 Windows 10 64 位的 MongoDB 下载

MongoDB 查找精确的数组匹配,但顺序无关紧要

如何使用 MongoDB 和 Mongoid 在 Rails 3 上进行适当的数据库测试 (TDD)

指定在 mongodb .js 脚本中使用哪个数据库

Mongodb Atlas:管理员未授权执行命令

我如何将 mongodb 与electron一起使用?