首页 > 解决方案 > 如何在更新时间 MongoDb 中将字段的总值添加为预聚合字段?

问题描述

我知道在 Mongo 中使用 $inc 可以计算和更新更新时间的数据计数,例如:

db.flights.update(  
  {
     $inc: {totalCnt: 1}
     $push: { price: {'t': time, 'p': newValue },
     $setOnInsert: { flightNo: "EN120" , airline="LFT"}
  },
  { upsert: true }
)

但是,我还需要计算price.p的总值(在上面的示例中)并将其添加并存储为更新时间的字段。我想知道是否可以在更新中使用 $sum 或 $add ?(实际上我希望能够在更新时间将平均价格存储为预聚合字段)。

例如,假设此文档存在于航班集合中:

{ "_id" : 1, "flightNo" : "EN120", "airline" : "LFT", "price" : [{"t": 120, "p": 2500}]}

执行更新(假设时间和价格的新值分别为1303000)命令后我需要的结果是:

{ "_id" : 1, "flightNo" : "EN120", "airline" : "LFT", "price" : [{'t': 120, 'p': 2500}, {'t': 130, 'p': 3000}], "totalCnt":2, "totalPrice": 5500}

在使用t=150p=2850执行另一个更新后,结果应该是:

{ "_id" : 1, "flightNo" : "EN120", "airline" : "LFT", "price" : [{'t': 120, 'p': 2500}, {'t': 130, 'p': 3000}, {'t': 150, 'p': 2850}], "totalCnt":3, "totalPrice": 8350}

谢谢

标签: mongodb

解决方案


对于 Mongo v4.2+,您可以使用流水线更新,请注意,您必须像这样更改更新结构:

db.collection.updateOne(
    { query },
    [
        {
            $set: {
                airline: {$ifNull: ["$airline", "LFT"]},
                flightNo: {$ifNull: ["$flightNo", "EN120"]},
                price: {$concatArrays: [{$ifNull: ["$price", []]}, [{'t': time, 'p': newValue}]]},
            }
        },
        {
            $set: {
                totalPrice: {
                    $reduce: {
                        input: "$price",
                        initialValue: 0,
                        in: {$sum: ["$$this.p", "$$value"]}
                    }
                },
                totalCnt: {$size: "$price"}
            }
        }
    ],
    {
        upsert: true
    }
)

对于较小的版本,您必须将其拆分为 2 个调用。首先获取,在代码中进行计算,然后更新。

- - 编辑 - -

一种更有效的计算方法totalPrice

db.collection.updateOne(
    { query },
    [
        {
            $set: {
                flightNo: {$ifNull: ["$flightNo", "EN120"]},
                totalPrice: {$sum: ["$totalPrice", newValue]},
                price: {$concatArrays: [{$ifNull: ["$price", []]}, [{'t': time, 'p': newValue}]]},
            }
        },
        {
            $set: {
                totalCnt: {$size: "$price"}
            }
        }
    ],
    {
        upsert: true
    }
)

推荐阅读