如何在同一文档中加入数组?

时间:2017-08-11 02:12:25

标签: 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",

      }
    ]
}

我尝试了$lookup的{​​{1}}或$unwind之类的各种内容,但我无法得到结果。

1 个答案:

答案 0 :(得分:1)

理想情况下,您需要$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"
        }
      }
    }
  }}
])

对于匹配的&#34;索引&#34;它基本上通过$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索引的第一个匹配元素返回$arrayElemAt。< / p>

在任何一种情况下,都不需要自我加入&#34;使用$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"
        }
    ]
}

一般来说,根本没有任何聚合运算符的原因,因为这种操作通常最好留在游标中进行后处理。事实上,因为你实际上是#34;添加&#34;要返回文档的数据,在通过网络发送文档后进行修改会更好。

作为上面显示为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)] }
        )
      )
    }
  )
)

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