MongoDB 从文档中的对象数组聚合 $lookup 管道查询,并匹配到单独集合文档的对象数组列表

问题描述 投票:0回答:1

游乐场链接 蒙戈游乐场

我想得到以下查询结果。

与起始匹配匹配的一张卡,其中 card.filters 以字符串数组开头,以过滤器集合中的新对象结束。

过滤器集合具有已启用的主过滤器、存档字段和子过滤器列表。 CARD 过滤器 [字符串] 列表将仅具有要启动的子过滤器字符串值,但这些值可能来自多个主过滤器列表(子过滤器值)。

  "cards": [
    {
      "cardId": "one-two-three",
      "filters": [
        "one",
        "two",
        "five"
      ]
    }
  ],
  "filters": [
    {
      "label": "filter-one-primary",
      "enabled": true,
      "archived": false,
      "list": [
        {
          "label": "One",
          "value": "one",
          "disabled": false
        },
        {
          "label": "Four",
          "value": "four",
          "disabled": false
        }
      ]
    },
    {
      "label": "filter-two-primary",
      "enabled": true,
      "archived": false,
      "list": [
        {
          "label": "Two",
          "value": "two",
          "disabled": false
        },
        {
          "label": "Five",
          "value": "five",
          "disabled": false
        }
      ]
    }
]

例如在上面的数据集中,一张卡片的起始过滤器数组可能为 [‘one’, ‘two’, ‘ Five’]

我希望在管道的开始部分首先根据主过滤器对象“enabled”:true和“archived”:false以及列表是否包含任何子过滤器来选择所有需要的过滤器。所以在上面的数据集中它会选择两者。

获得过滤器后,我们需要将它们转换为第一个返回的 CARD 中的以下内容。

所以使用上面的例子,返回的 CARD 会有这个。

[
  {
    "_id": ObjectId("5a934e000102030405000000"),
    "cardId": "one-two-three",
    "filters": [
        {
             primary: "filter-one-primary", // Used to be from filter object.label
             secondary: "One", // Used to be from filter object.[list].value
             id: "one", // Used to be from filter object.[list].value
             disabled: false // Used to be from filter object.[list].disabled
        },
              primary: "filter-two-primary", // Used to be from filter object.label
             secondary: "Two", // Used to be from filter object.[list].value
             id: "two", // Used to be from filter object.[list].value
             disabled: false // Used to be from filter object.[list].disabled
        {
        },
        {
              primary: "filter-two-primary", // Used to be from filter object.label
             secondary: "Five", // Used to be from filter object.[list].value
             id: "five", // Used to be from filter object.[list].value
             disabled: false // Used to be from filter object.[list].disabled
        }
    ]
  }
]

在 $lookup 管道中,我们将匹配

// DATA

db={
  "cards": [
    {
      "cardId": "one-two-three",
      "filters": [
        "four",
        "five",
        "six"
      ]
    }
  ],
  "filters": [
    {
      "label": "filter-one-primary",
      "enabled": true,
      "archived": false,
      "list": [
        {
          "label": "One",
          "value": "one",
          "disabled": false
        },
        {
          "label": "Four",
          "value": "four",
          "disabled": false
        }
      ]
    },
    {
      "label": "filter-two-primary",
      "enabled": true,
      "archived": false,
      "list": [
        {
          "label": "Two",
          "value": "two",
          "disabled": false
        },
        {
          "label": "Five",
          "value": "five",
          "disabled": false
        }
      ]
    },
    {
      "label": "filter-three-primary",
      "enabled": true,
      "archived": false,
      "list": [
        {
          "label": "Three",
          "value": "three",
          "disabled": false
        },
        {
          "label": "SiX",
          "value": "six",
          "disabled": false
        }
      ]
    }
  ]
}
db.cards.aggregate([
  {
    $match: {
      "cardId": "one-two-three"
    }
  },
  {
    $lookup: {
      from: "filters",
      "let": {
        "id": "filters"
      },
      pipeline: [
        {
          $match: {
            $and: [
              {
                $expr: {
                  $in: [
                    "$$id",
                    "$list.value"
                  ]
                },
                "enabled": true,
                "archived": false
              }
            ]
          }
        }
      ],
      as: "filters"
    }
  }
])
mongodb match aggregate pipeline lookup
1个回答
0
投票

在您的

$lookup
管道中:

  1. $match
    - 您的
    $$id
    是来自
    filters
    数组值的数组字段。因此,您不应使用
    $in
    运算符,而应使用
    $setIntersection
    $size
    运算符来检查数组之间是否存在任何相交/匹配的元素。

  2. $unwind
    - 将
    list
    数组解构为多个文档。

  3. $match
    - 通过匹配
    list.value
    来过滤文档。

  4. $project
    - 装饰要在
    filters
    数组中输出的文档。

db.cards.aggregate([
  {
    $match: {
      "cardId": "one-two-three"
    }
  },
  {
    $lookup: {
      from: "filters",
      "let": {
        "id": "$filters"
      },
      pipeline: [
        {
          $match: {
            $and: [
              {
                $expr: {
                  $gt: [
                    {
                      $size: {
                        $setIntersection: [
                          "$$id",
                          "$list.value"
                        ]
                      }
                    },
                    0
                  ]
                },
                "enabled": true,
                "archived": false
              }
            ]
          }
        },
        {
          $unwind: "$list"
        },
        {
          $match: {
            $expr: {
              $in: [
                "$list.value",
                "$$id"
              ]
            }
          }
        },
        {
          $project: {
            _id: 0,
            primary: "$label",
            secondary: "$list.label",
            id: "$list.value",
            disabled: "$list.disabled"
          }
        }
      ],
      as: "filters"
    }
  }
])

演示@Mongo Playground

© www.soinside.com 2019 - 2024. All rights reserved.