Как фильтровать в агрегации мангуста при объединении на основе двух равных полей, хранящихся в массиве объектов?

#mongodb #mongoose #aggregation-framework

#mongodb #mongoose #агрегация-фреймворк

Вопрос:

Допустим, у меня есть два документа в коллекции продуктов:

 {
  _id: ObjectId("abc"), name: "Pizza",
  attributes: [
    {salePrice: 250, size: "Small"},
    {salePrice: 300, size: "Medium"},
    {salePrice: 350, size: "Large"}
  ]
},
{
  _id: ObjectId("xyz"), name: "Burger",
  attributes: [
    {salePrice: 100, size: "Regular"},
    {salePrice: 150, size: "Large"}
  ]
}
 

Я добавил товары в корзину, поэтому документ в коллекции корзины выглядит следующим образом:

 {
  cartProducts: [
    { productId: ObjectId("xyz"), type: "Large", quantity: 5 },
    { productId: ObjectId("abc"), type: "Regular", quantity: 2 }, 
  ]
}
 

Я хочу получить сведения о корзине (все элементы корзины) с деталями, основанными на поле «тип» корзины.cartProducts соответствуют полю «размер» product.attributes. Таким образом, результат будет выглядеть следующим образом:

  cart items
{
  cartDetails: [
    {
      name: "Pizza", quantity: 5, salePrice: 350, productId: "xyz"
    },
    {
      name: "Burger", quantity: 2, salePrice: 100, productId: "abc"
    }
  ]
}
 

Как я могу это сделать, используя aggregate. Каковы следующие этапы?

 Cart.aggregate([
  { $unwind: { path: "$cartProducts" } },
  {$lookup:{ from:"products", localField:"cartProducts.productId", foreignField:"_id", as:"products" } },
  { $unwind: { path: "$products", includeArrayIndex: "arrayIndex", preserveNullAndEmptyArrays: true } }
]);
 

Ответ №1:

  • $lookup передать массив productId как localField
  • теперь у вас есть 2 массива, один cartProducts и второй products ,
  • $map для повторения цикла cartProducts
  • $reduce чтобы повторить цикл products и проверить условие, если productId совпадение, перейдите к следующему шагу
  • $reduce для итерации внешнего вида attributes и проверки состояния size и type
  • $mergeObjects чтобы объединить объекты с новыми полями
 Cart.aggregate([
  {
    $lookup: {
      from: "products",
      localField: "cartProducts.productId",
      foreignField: "_id",
      as: "products"
    }
  },
  {
    $project: {
      cartProducts: {
        $map: {
          input: "$cartProducts",
          as: "p",
          in: {
            $mergeObjects: [
              "$p",
              {
                $reduce: {
                  input: "$products",
                  initialValue: {},
                  in: {
                    $cond: [
                      { $eq: ["$this._id", "$p.productId"] },
                      {
                        name: "$this.name",
                        salePrice: {
                          $reduce: {
                            input: "$this.attributes",
                            initialValue: 0,
                            in: {
                              $cond: [
                                { $eq: ["$this.size", "$p.type"] },
                                "$this.salePrice",
                                "$value"
                              ]
                            }
                          }
                        }
                      },
                      "$value"
                    ]
                  }
                }
              }
            ]
          }
        }
      }
    }
  }
])
 

Игровая площадка


Второй вариант в соответствии с вашей попыткой,

  • $reduce чтобы повторить цикл products.attributes массива, проверьте условие type и size и верните обязательные поля,
  • $mergeObjects для объединения cartProducts с новыми полями
 Cart.aggregate([
  { $unwind: "$cartProducts" },
  {
    $lookup: {
      from: "products",
      localField: "cartProducts.productId",
      foreignField: "_id",
      as: "products"
    }
  },
  { $unwind: "$products" },
  {
    $project: {
      cartProducts: {
        $mergeObjects: [
          "$cartProducts",
          {
            $reduce: {
              input: "$products.attributes",
              initialValue: {},
              in: {
                $cond: [
                  { $eq: ["$this.sise", "$caartProducts.type"] },
                  {
                    name: "$products.name",
                    salePrice: "$this.salePrice"
                  },
                  "$value"
                ]
              }
            }
          }
        ]
      }
    }
  }
])
 

Игровая площадка

Комментарии:

1. Я получил правильный ответ, используя указанное объяснение, спасибо.