【问题标题】:Mongodb $subtract document value from the next oneMongodb $从下一个中减去文档值
【发布时间】:2017-09-05 19:13:22
【问题描述】:

我有这样一个文档集合:

{ _id: 1, Meters: { gasmeter: 1000.0 } }
{ _id: 2, Meters: { gasmeter: 1007.0 } }
{ _id: 3, Meters: { gasmeter: 1010.0 } }

我正试图了解煤气表元素之间的区别:

{ difference: 7 } // Difference between _id=1 and _id=2
{ difference: 3 } // Difference between _id=2 and _id=3

我试过了:

db.MeterData.aggregate([{$project: { item: 1, difference: {$subtract: [ {$add: [ "$Meters.gasmeter","$Meters.gasmeter" ] }, "$Meters.gasmeter" ] }}}])

但这不起作用。我仍然得到相同的值。

知道如何使用 mongodb 进行聚合吗?

【问题讨论】:

  • 您不能对来自聚合框架中不同文档的值进行操作。对于“小而琐碎”的示例,您可以 $push 将所有文档放入一个数组中,并使用 $reduce 现在在“单个”文档结果中迭代数组值。但是你在这里真正谈论的是更自然地用“光标迭代”来完成。因为您只需保留游标中读取的最后一个文档的值,并使用变量中存储的值对下一个文档进行计算。不是你要求数据库直接返回的东西。
  • 我明白,但是使用大数据集的迭代是不是太昂贵了? (谈论大约 100k 的文件)
  • 您要求的是“每个文档之间的差异”。这不像你要求服务器减少任何东西。它仍然是 100K 文件。您只需要返回具有您希望知道的值的属性。这是非常合乎逻辑的,因此您需要仔细考虑。这不是“聚合”。

标签: mongodb mongodb-query aggregation-framework


【解决方案1】:

因为我不完全确定您希望如何解决问题(在 C# 或 mongo 本身中)。这是我在 Mongo 中提出的。

db.MeterData.find().forEach(
    function (doc) {
    var next = db.Sum.findOne({
            _id: {
                "$gt": NumberInt(doc._id)
            }
        })
    if (next != null) {
        var diff = next.Meters.gasmeter - doc.Meters.gasmeter;
        printjson("{ difference : " + diff + "} - Difference between Id=" + doc._id + " and Id=" + next._id);
    }
})

返回

"{ difference : 7} - Difference between Id=1 and Id=2"

"{ difference : 3} - Difference between Id=2 and Id=3"

希望对你有所帮助。

【讨论】:

【解决方案2】:

从Mongo 5 开始,这是新的$setWindowFields 聚合运算符的完美用例:

// { id: 1, gasmeter: 1000 }
// { id: 2, gasmeter: 1007 }
// { id: 3, gasmeter: 1010 }
db.collection.aggregate([

  { $setWindowFields: {
    sortBy: { id: 1 },
    output: {
      difference: {
        $push: "$gasmeter",
        window: { range: [-1, "current"] }
      }
    }
  }},
  // { id: 1, gasmeter: 1000, difference: [1000] }
  // { id: 2, gasmeter: 1007, difference: [1000, 1007] }
  // { id: 3, gasmeter: 1010, difference: [1007, 1010] }

  { $match: { $expr: { $eq: [{ $size: "$difference" }, 2] } } },
  // { id: 2, gasmeter: 1007, difference: [1000, 1007] }
  // { id: 3, gasmeter: 1010, difference: [1007, 1010] }

  { $set: {
    difference: { $subtract: [{ $last: "$difference" }, { $first: "$difference" }] }
  }}
])
// { id: 2, gasmeter: 1007, difference: 7 }
// { id: 3, gasmeter: 1010, difference: 3 }

这个:

  • 以$setWindowFields 聚合阶段开始,在每个文档中添加difference 字段(output: { difference: { ... }})
    • 作为 $push 的数组 gasmeters ($sum: "$gasmeter")
    • 来自指定范围的文档(window),这里是"current"文档和上一个"-1":window: { range: [-1, "current"] }
  • 然后过滤掉第一个没有先前文档的文档(即,我们无法将其值与先前文档的值进行比较):
    • 为此,我们只需检查前一阶段生成的数组大小是否为 2:{ $match: { $expr: { $eq: [{ $size: "$difference" }, 2] } } },
  • 最后将数组中的2个值相减得到实际差值:$subtract: [{ $last: "$difference" }, { $first: "$difference" }]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-17
    • 2019-07-26
    相关资源
    最近更新 更多