#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. Я получил правильный ответ, используя указанное объяснение, спасибо.