MongoDB $在双重嵌套对象数组上查找

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

我有一个数据模型,其中每个产品都有许多变体,每个变体都有许多修改。在数据库中它看起来像这样:

const mods = db.modifications.insertMany([
  {
    title: 'Modification #1',
    image: 'img1.png',
  },
  {
    title: 'Modification #2',
    image: 'img2.png',
  },
  {
    title: 'Modification #3',
    image: 'img3.png',
  },
])

db.products.insertOne({
  slug: 'product1',
  title: 'Product #1',
  variants: [
    {
      size: 20,
      price: 200,
      modifications: [
        { id: mods.insertedIds[0], price: 10 },
        { id: mods.insertedIds[1], price: 15 },
      ],
    },
    {
      size: 30,
      price: 250,
      modifications: [
        { id: mods.insertedIds[0], price: 15 },
        { id: mods.insertedIds[2], price: 20 },
      ],
    },
  ],
})

https://mongoplayground.net/p/6jmEv2Q2aZO

我想做的是

db.products.aggregate([
  { $match: { slug: 'product1' } },
  // ?
])

得到如下所示的结果

const result = {
  slug: 'product1',
  title: 'Product #1',
  variants: [
    {
      size: 20,
      price: 200,
      modifications: [
        { _id: '…', title: 'Modification #1', image: '…', price: 10 },
        { _id: '…', title: 'Modification #2', image: '…', price: 15 },
      ],
    },
    {
      size: 30,
      price: 250,
      modifications: [
        { _id: '…', title: 'Modification #2', image: '…', price: 15 },
        { _id: '…', title: 'Modification #3', image: '…', price: 20 },
      ],
    },
  ],
}

如何在 MongoDB 中实现?

我尝试过

$unwind
两次,然后
$lookup

db.products.aggregate([
  { $match: { slug: 'product1' } },
  { $unwind: '$variants' },
  { $unwind: '$variants.modifications' },
  {
    $lookup: {
      from: 'modifications',
      localField: 'variants.modifications.id',
      foreignField: '_id',
      let: { price: '$variants.modifications.price' },
      pipeline: [{ $addFields: { price: '$$price' } }],
      as: 'modifications',
    },
  },
])

但不知道如何

$group
(?)恢复该数据。

此外,还有 具有工作解决方案的类似问题。但就我而言,

modifications
数组不仅仅是 id 数组,而且在其元素(
price
字段)中包含数据,我需要以某种方式将其包含在结果中。

mongodb join aggregate
1个回答
0
投票

无需

$unwind
阶段即可实现。

  1. $match

  2. $lookup
    - 从 modifications 集合中使用
    _id
    获取匹配的文档
    modIds
    variants.modifications.id)
    )并输出为
    modifications
    数组。

  3. $set
    - 设置
    variants
    字段。

    3.1。

    $map
    - 通过合并当前
    variants
    (变体)对象和结果
    3.1.1
    中的对象来迭代 v 数组。

    3.1.1.

    $map
    - 通过迭代
    modifications
    数组,合并当前
    modifications
    (修改)对象和结果
    3.1.1.1
    中的对象,该对象包含 m 数组。

    3.1.1.1。

    $first
    - 从结果中获取第一个匹配元素3.1.1.1.1.

    3.1.1.1.1。

    $filter
    - 使用
    modifications
    从(根)
    m.id
    数组中过滤匹配文档。

  4. $unset
    - 删除“modifications”和“variants.modifications.id”字段。

db.products.aggregate([
  {
    "$match": {
      slug: "product1"
    }
  },
  {
    "$lookup": {
      "from": "modifications",
      "let": {
        modIds: {
          $reduce: {
            input: "$variants.modifications.id",
            initialValue: [],
            in: {
              $concatArrays: [
                "$$value",
                "$$this"
              ]
            }
          }
        }
      },
      "pipeline": [
        {
          "$match": {
            $expr: {
              $in: [
                "$_id",
                "$$modIds"
              ]
            }
          }
        }
      ],
      "as": "modifications"
    }
  },
  {
    $set: {
      variants: {
        $map: {
          input: "$variants",
          as: "v",
          in: {
            $mergeObjects: [
              "$$v",
              {
                modifications: {
                  $map: {
                    input: "$$v.modifications",
                    as: "m",
                    in: {
                      $mergeObjects: [
                        "$$m",
                        {
                          $first: {
                            $filter: {
                              input: "$modifications",
                              cond: {
                                $eq: [
                                  "$$this._id",
                                  "$$m.id"
                                ]
                              }
                            }
                          }
                        }
                      ]
                    }
                  }
                }
              }
            ]
          }
        }
      }
    }
  },
  {
    $unset: [
      "modifications",
      "variants.modifications.id"
    ]
  }
])

演示@Mongo Playground

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