You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MongoDB关联数组元素聚合查询并计算总价的问题

MongoDB聚合查询:关联集合并计算物料总价

我有两个互相关联的MongoDB集合:semiproducts和materials。semiproducts集合中mater数组的id字段与materials集合的_id字段关联。我需要通过聚合查询关联获取对应物料信息,并为semiproducts文档添加totalPrice字段,该字段为关联物料的总价之和。我尝试了一段聚合查询语句,但未得到预期结果,寻求正确实现方案。


集合结构

semiproducts集合

semiproducts = [
  {
    _id: "64afad9eda7e337a51b304c8",
    name: "Cream",
    description: "One Degree",
    mater: [
      {
        mtNumber: 1000,
        id: "64afa9dcda7e337a51b30467",
      },
      {
        mtNumber: 150,
        id: "64afaa08da7e337a51b3046d",
      },
      {
        mtNumber: 250,
        id: "64afa9a4da7e337a51b3045e",
      },
    ],
  },
];

materials集合

materials = [
  {
    _id: "64afaa08da7e337a51b3046d",
    name: "Un",
    type: "Gıda",
    amount: 1000,
    price: 13.5,
    description: "21",
    date: "2023-07-05T00:00:00.000Z",
  },
  {
    _id: "64afa9a4da7e337a51b3045e",
    name: "Toz Şeker",
    type: "Gıda",
    amount: 1000,
    price: 22,
    date: "2023-07-13T00:00:00.000Z",
  },
  {
    _id: "64afa9dcda7e337a51b30467",
    name: "Tereyağ",
    type: "Gıda",
    amount: 1000,
    price: 170,
    date: "2023-07-13T00:00:00.000Z",
  },
];

预期结果

semiproducts = [
  {
    _id: "64afad9eda7e337a51b304c8",
    name: "Cream",
    description: "One Degree",
    mater: [
      {
        mtNumber: 1000,
        id: "64afa9dcda7e337a51b30467",
      },
      {
        mtNumber: 150,
        id: "64afaa08da7e337a51b3046d",
      },
      {
        mtNumber: 250,
        id: "64afa9a4da7e337a51b3045e",
      },
    ],
    totalPrice: 1253 // 关联物料的总价之和
  },
];

尝试的聚合查询语句

[
  {
    $lookup: {
      from: "materials",
      let: { mat_id: "$mater.id" },
      pipeline: [
        {
          $match: {
            $expr: {
              $in: ["$_id", "$$mat_id"],
            },
          },
        },
      ],
      as: "mat_info",
    },
  },
  {
    $addFields: {
      total: { $sum: "$mat_info.price" },
    },
  },
];

问题分析与正确方案

你的查询仅直接求和物料的price字段,但未结合semiproducts中mater数组的mtNumber(使用数量)进行计算。要得到正确的totalPrice,需要将每个mater元素与对应物料的price关联,计算单种物料的总价后再求和。

以下是正确的聚合查询:

db.semiproducts.aggregate([
  // 关联materials集合,获取所有关联物料信息
  {
    $lookup: {
      from: "materials",
      localField: "mater.id",
      foreignField: "_id",
      as: "mat_info"
    }
  },
  // 计算totalPrice:遍历mater数组,匹配对应物料价格并计算总价后求和
  {
    $addFields: {
      totalPrice: {
        $sum: {
          $map: {
            input: "$mater",
            as: "item",
            in: {
              // 示例按「使用数量 × 单位价格」计算,单位价格 = price/amount
              $multiply: [
                "$$item.mtNumber",
                {
                  $divide: [
                    {
                      $getField: {
                        field: "price",
                        input: {
                          $first: {
                            $filter: {
                              input: "$mat_info",
                              cond: { $eq: ["$$this._id", "$$item.id"] }
                            }
                          }
                        }
                      }
                    },
                    {
                      $getField: {
                        field: "amount",
                        input: {
                          $first: {
                            $filter: {
                              input: "$mat_info",
                              cond: { $eq: ["$$this._id", "$$item.id"] }
                            }
                          }
                        }
                      }
                    }
                  ]
                }
              ]
            }
          }
        }
      }
    }
  },
  // 可选:移除临时的mat_info字段,保持文档简洁
  { $project: { mat_info: 0 } }
])

说明

  1. $lookup关联:使用localField和foreignField直接关联两个集合的字段,获取所有关联物料到mat_info数组。
  2. 总价计算逻辑:
    • 用$map遍历mater数组的每个元素;
    • 用$filter从mat_info中匹配当前元素对应的物料;
    • 根据业务需求计算单种物料的总价(示例中是mtNumber乘以单位价格,即price/amount);
    • 用$sum将所有单物料总价求和得到totalPrice。
  3. 若你的业务中price就是mtNumber对应的单位价格,无需按amount换算,可将$multiply部分简化为:
    $multiply: [
      "$$item.mtNumber",
      {
        $getField: {
          field: "price",
          input: {
            $first: {
              $filter: {
                input: "$mat_info",
                cond: { $eq: ["$$this._id", "$$item.id"] }
              }
            }
          }
        }
      }
    ]
    

内容的提问来源于stack exchange,提问作者Mehmet Altan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 15:17:07