我面临着在 MongoDB 模式模型上完成聚合函数的问题,情况是我确实有具有以下形式的模型订单。
我想做的是按药品名称过滤总销售额,例如,如果我有 panadol、catafast、test 我想知道我卖了多少Panadol等等。 我正在尝试使用聚合函数对所有已完成的订单进行分组并过滤它们,然后尝试通过数组中的 id 查找药物名称。但是我得到了一个空数组,并且我对我的数据非常确定。我不确定函数中的管道。
const getSalesDataByMedicine = async (req, res) => {
try {
const medicineSales = await Orders.aggregate([
{
$match: {
status: "Completed"
}
},
{
$unwind: "$items"
},
{
$group: {
_id: "$items.MedicineId",
totalQuantity: { $sum: "$items.Quantity" },
totalAmount: { $sum: { $multiply: ["$items.Quantity", "$amount"] } }
}
},
{
$lookup: {
from: "medicine", // Replace with the actual name of your Medicine model's collection
localField: "_id",
foreignField: "MedicineId", // Assuming Medicine _id is used in MedicineId field
as: "medicineData"
}
},
{
$unwind: "$medicineData"
},
{
$project: {
_id: 0,
medicineId: "$_id",
medicineName: "$medicineData.name", // Adjust to your actual field name in Medicine model
totalQuantity: 1,
totalAmount: 1
}
}
]);
return res.status(200).json(medicineSales);
} catch (err) {
console.error("Error fetching medicine sales data:", err);
return res.status(500).json({ error: "Internal Server Error" });
}
};
提前致谢,
根据您当前的查询,您需要进行以下更改:
在
items.MedicineId
阶段将ObjectId
转换为$group
。
外国字段是
_id
,即 medicine集合中文档中的
_id
字段,但不是 MedicineId
。
[
...,
{
$group: {
_id: {
$toObjectId: "$items.MedicineId"
},
...
}
},
{
$lookup: {
from: "medicine",
// Replace with the actual name of your Medicine model's collection
localField: "_id",
foreignField: "_id",
// Assuming Medicine _id is used in MedicineId field
as: "medicineData"
}
},
...
]
请注意,您对每种产品的总销售额的计算不正确,因为您乘以
订单中的
amount
。它应该乘以药品的单价。 (医学文档 -> price
)
totalAmount: { $sum: { $multiply: ["$items.Quantity", "$amount"] } }
所以你的查询应该是:
db.order.aggregate([
{
$match: {
status: "Completed"
}
},
{
$unwind: "$items"
},
{
$group: {
_id: {
$toObjectId: "$items.MedicineId"
},
totalQuantity: {
$sum: "$items.Quantity"
}
}
},
{
$lookup: {
from: "medicine",
// Replace with the actual name of your Medicine model's collection
localField: "_id",
foreignField: "_id",
// Assuming Medicine _id is used in MedicineId field
as: "medicineData"
}
},
{
$unwind: "$medicineData"
},
{
$project: {
_id: 0,
medicineId: "$_id",
medicineName: "$medicineData.name",
// Adjust to your actual field name in Medicine model
totalQuantity: 1,
totalAmount: {
$multiply: [
"$totalQuantity",
"$medicineData.price"
]
}
}
}
])
另外,正如评论中提到的,我认为将 medicine 集合(基础)与 order 集合相结合,可以通过消除那些查询成本高昂的
$uwind
阶段来获得更好的性能。
db.medicine.aggregate([
{
$lookup: {
from: "order",
let: {
medicineId: {
$toString: "$_id"
}
},
pipeline: [
{
$match: {
$expr: {
$and: [
{
$eq: [
"$status",
"Completed"
]
},
{
$in: [
"$$medicineId",
"$items.MedicineId"
]
}
]
}
}
},
{
$set: {
items: {
$filter: {
input: "$items",
cond: {
$eq: [
"$$this.MedicineId",
"$$medicineId"
]
}
}
}
}
}
],
"as": "orders"
}
},
{
$match: {
orders: {
$ne: []
}
}
},
{
$project: {
_id: 0,
medicineId: "$_id",
medicineName: "$name",
// Adjust to your actual field name in Medicine model
totalQuantity: {
$sum: {
$reduce: {
input: "$orders",
initialValue: [],
in: {
$concatArrays: [
"$$value",
"$$this.items.Quantity"
]
}
}
}
},
totalAmount: {
$multiply: [
{
$sum: {
$reduce: {
input: "$orders",
initialValue: [],
in: {
$concatArrays: [
"$$value",
"$$this.items.Quantity"
]
}
}
}
},
"$price"
]
}
}
}
])
$reduce
的用法是将items
的嵌套数组展平,orders
数组中每个文档中都是一个数组字段。