MongoDB 复杂聚合函数

问题描述 投票:0回答:1

我面临着在 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" });
    }


};

提前致谢,

javascript mongodb aggregation-framework
1个回答
0
投票

根据您当前的查询,您需要进行以下更改:

  1. items.MedicineId
    阶段将
    ObjectId
    转换为
    $group

  2. 外国字段是

    _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"
        ]
      }
    }
  }
])

演示解决方案1 @ Mongo Playground

另外,正如评论中提到的,我认为将 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
数组中每个文档中都是一个数组字段。

演示解决方案 2 @ Mongo Playground

© www.soinside.com 2019 - 2024. All rights reserved.