mongodb - 如何在同一文档中连接数组?

标签 mongodb mongodb-query aggregation-framework nosql

我想使用两个数组的 ID 将数据合并到一个集合中。

示例如下。

{
    "_id": ObjectId ("5976fd2eb0adec0a32fa9831"),
       "People": [
          {
            "_id": 1,      <--- ID
            "Name": "jane"
          },
          {
            "_id": 2,      <--- ID
            "Name": "Mark"
          }
       ],
       "Contents": [
          {
            "userID":  2,   <--- People ID
            "Text": "111"
          },
          {
            "userID":  1,   <--- People ID
            "Text": "Hi"
          }
       ]
}

我想把上面的文件做成下面的样子。

{
    "_id": ObjectId ("5976fd2eb0adec0a32fa9831"),
    "People": [
       {
          "_id": 1,
          "Name" : "Jane"
       },
       {
          "_id": 2,
          "Name": "Mark"
       }
    ],
    "Contents": [
       {
          "userID": 2,
          "Name": "Mark",    <-- Adding
          "Text": "111",

      },
       {
          "userID": 1,
          "Name": "Jane",    <-- Adding
          "Text": "Hi",

      }
    ]
}

我尝试了各种方法,例如 .aggregate()$lookup$unwind 但我无法得到结果。

最佳答案

你想要$map$indexOfArray理想情况下:

db.collection.aggregate([
  { "$addFields": {
    "Contents": {
      "$map": {
        "input": "$Contents",
        "as": "c",
        "in": {
          "userID": "$$c.userID",
          "Name": {
            "$arrayElemAt": [
              "$People.Name",
              { "$indexOfArray": [ "$People._id", "$$c.userID" ] }
            ]
          },
          "Text": "$$c.Text"
        }
      }
    }
  }}
])

这基本上是通过 $arrayElemAt 从另一个数组中获取值对于 $indexOfArray 返回的匹配“索引” .

如果您的 MongoDB 需要回退到没有该运算符的版本,那么您可以使用 $filter相反:

db.collection.aggregate([
  { "$addFields": {
    "Contents": {
      "$map": {
        "input": "$Contents",
        "as": "c",
        "in": {
          "userID": "$$c.userID",
          "Name": {
            "$arrayElemAt": [
              { "$map": {
                "input": { 
                  "$filter": {
                    "input": "$People",
                    "as": "p",
                    "cond": { "$eq": [ "$$p._id", "$$c.userID" ] }
                  }
                },
                "as": "p",
                "in": "$$p.Name"
              }},
              0
            ]
          },
          "Text": "$$c.Text"
        }
      }
    }
  }}
])

基本上你在哪里$filter比较其他数组的结果,并简单地返回 0 索引的 first 匹配元素 $arrayElemAt .

无论哪种情况,都无需使用 $lookup 进行“自加入” ,这是最好避免的真正不必要的开销。

从问题中的文档中,您可以获得以下信息:

/* 1 */
{
    "_id" : ObjectId("5976fd2eb0adec0a32fa9831"),
    "People" : [ 
        {
            "_id" : 1.0,
            "Name" : "jane"
        }, 
        {
            "_id" : 2.0,
            "Name" : "Mark"
        }
    ],
    "Contents" : [ 
        {
            "userID" : 2.0,
            "Name" : "Mark",
            "Text" : "111"
        }, 
        {
            "userID" : 1.0,
            "Name" : "jane",
            "Text" : "Hi"
        }
    ]
}

但一般来说,任何聚合运算符都没有这样的理由,因为这种操作通常最好留给游标中的后处理。事实上,由于您实际上是在向要返回的文档“添加”数据,因此最好在文档通过网络发送后进行修改。

作为上面显示为 shell 的 JavaScript 的常见习语:

db.collection.find().map( d => 
  Object.assign(
    d,
    {
      "Contents": d.Contents.map( c => 
        Object.assign(c, 
          { "Name": d.People.map(p => p.Name)[d.People.map(p => p._id).indexOf(c.userID)] }
        )
      )
    }
  )
)

产生完全相同的结果,并且通常更容易阅读和解释

关于mongodb - 如何在同一文档中连接数组?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45625914/

相关文章:

node.js - 在 Node 中存储 mongoDB 的收集结果

node.js - 查找 ObjectId _id 但 Schema 已将 _id 定义为 String

mongodb - 为什么 $lookup 中的 "as"会替换整个集合?

mongodb - 使用数据在最后一个序列中首次出现

node.js - MongoDB 查询子文档中的不同内容

mongodb & 最大连接数

使用 Haskell 驱动程序进行 MongoDB 全文搜索

带有 $in 的 mongodb 聚合查询的 Java 代码

javascript - 查询嵌套对象键

java - 在 Spring Data MongoDB 中返回流时指定游标选项?