使用MongoDB聚合管道将嵌套数组元素投影到顶层

dauxcl2d  于 2023-01-16  发布在  Go
关注(0)|答案(2)|浏览(137)

我有一个groups集合,其中包含以下形式的文档

{
    "_id": "g123"
    ...,
    "invites": [
        {
            "senderAccountId": "a456",
            "recipientAccountId": "a789"
        },
        ...
    ]
}

我希望能够列出用户收到的所有邀请。
我想到在groups集合上使用聚合管道,过滤所有组,只返回用户被邀请加入的组。

db.groups.aggregate([
    {
        $match: {
            "invites.recipientAccountID": "<user-id>"
        }
    }
])

最后,我想投影这个组数组,以得到一个形式为

[
    {
         "senderAccountId": "a...",
         "recipientAccountId": "<user-id>",
         "groupId": "g...", // Equal to "_id" field of document.
    },
    ...
]

但是我错过了聚合管道中将嵌套的senderAccountIdrecipientAccountId字段放到顶层的“投影”步骤。我在网上看到过MongoDB查询和聚合管道中投影的示例,但是我找不到将文档数组字段中先前匹配的元素投影到顶层的示例。
我曾想过使用Array Update Operators来引用匹配的元素,但使用此方法无法获得任何有意义的进展。

hgtggwj0

hgtggwj01#

有多种方法可以做到这一点,使用unwindproject的组合也可以。Unwind将为每个对象创建一个对象,project允许您选择如何使用当前变量来构造结果。

db.collection.aggregate([
  {
    "$unwind": "$invites"
  },
  {
    "$match": {
      "invites.recipientAccountId": "a789"
    }
  },
  {
    "$project": {
      recipientAccountId: "$invites.recipientAccountId",
      senderAccountId: "$invites.senderAccountId",
      groupId: "$_id",
      _id: 0 // don't show _id key:value
    }
  }
])

您还可以使用尼姆罗德serok的$replaceRoot来代替$project

{$replaceRoot: {newRoot: {$mergeObjects: ["$invites", {group: "$_id"}]}}}

playground
尼姆罗德serok的解决方案可能更好一点,因为我的解决方案首先展开它,然后匹配它,但我相信我的解决方案更具可读性

kupeojn6

kupeojn62#

我觉得你想要的是$replaceRoot

db.collection.aggregate([
  {$match: {"invites.recipientAccountId": "a789"}},
  {$set: {
      invites: {$first: {
          $filter: {
            input: "$invites",
            cond: {$eq: ["$$this.recipientAccountId", "a789"]}
          }
      }}
  }},
  {$replaceRoot: {newRoot: {$mergeObjects: ["$invites", {group: "$_id"}]}}}
])

了解它在playground example上的工作原理

相关问题