MongoDB $lookup on double nested array of objects

oymdgrw7  于 2023-11-17  发布在  Go
关注(0)|答案(1)|浏览(252)

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

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' } },
  // ?
])


得到这样的结果

{
  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(?)数据返回。
还有a similar question with the working solution,在我的例子中,modifications数组不仅仅是一个id数组,它的元素(price字段)中有数据,我需要以某种方式将其包含在结果中。

4szc88ey

4szc88ey1#

您可以在没有$unwind阶段的情况下实现。

  1. $match
  2. $lookup-从 modifications 集合中获取匹配的文档,其中_id位于扁平化的modIdsvariants.modifications.id))中,并输出为modifications数组。
  3. $set-设置variants字段。
    3.1. $map-通过合并当前v(变量)对象和结果中的对象来迭代variants数组 3.1.1
    3.1.1. $map-通过迭代modifications数组,合并当前m(修改)对象和结果中的对象,对象包含modifications数组 3.1.1.1
    3.1.1.1. $first-从结果中获取第一个匹配元素 3.1.1.1.1.
    3.1.1.1.1. $filter-使用m.id从(根)modifications数组中筛选匹配文档。
  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"
    ]
  }
])

字符串
Demo @ Mongo Playground

相关问题