Вы можете использовать агрегацию ниже:
db.collection.aggregate([
{
$group: {
_id: "$date",
income: { $sum: "$income" },
num_orders: { $sum: "$num_orders" },
avg_order_amount: { $avg: "$avg_order_amount" },
orders: { $push: "$orders" },
orderTypes: { $push: "$orders.type" }
}
},
{
$project: {
_id: 0,
date: "$_id",
income: 1,
num_orders: 1,
avg_order_amount: 1,
orders: {
$map: {
input: { $reduce: { input: "$orderTypes", initialValue: [], in: { $setUnion: [ "$$this", "$$value" ] } } },
as: "orderType",
in: {
$let: {
vars: {
currentTypeOrders: {
$filter: {
input: { $reduce: { input: "$orders", initialValue: [], in: { $concatArrays: [ "$$this", "$$value" ] } } },
cond: { $eq: [ "$$this.type", "$$orderType" ] }
}
}
},
in: {
avg_product_price: { "$avg": "$$currentTypeOrders.avg_product_price" },
income: { "$sum": "$$currentTypeOrders.income" },
num_products: { "$sum": "$$currentTypeOrders.num_products" },
type: "$$orderType",
products: {
$let: {
vars: {
products: { $reduce: { input: "$$currentTypeOrders.products", initialValue: [], in: { $concatArrays: [ "$$this", "$$value" ] } } }
},
in: {
$map: {
input: { $setUnion: [ "$$products.name", [] ] },
as: "product",
in: {
$let: {
vars: {
currentProducts: { $filter: { input: "$$products", cond: { $eq: [ "$$this.name", "$$product" ] } } }
},
in: {
name: "$$product",
amount: { $sum: "$$currentProducts.amount" }
}
}
}
}
}
}
}
}
}
}
}
}
}
}
])
Обычно мы можем использовать операторы $sum
и $avg
для верхнего уровня как часть оператора $ group .
Это становится более проблематичным, когда мы хотим вычислить такие агрегаты для вложенных массивов. Вы можете использовать $ reduce вместе с $ setUnion , чтобы сгладить массив массивов и получить уникальные значения, такие как direct, online
.
Получив их, вы можете использовать $ let и $ filter , чтобы получить только те заказы, которые относятся к определенной категории c, и снова использовать $sum, $avg
для вычислить значения для вложенного массива.
Один и тот же трюк должен быть выполнен дважды, поскольку массив products
вложен в элементы другого массива.
Пн go Детская площадка