首页 > 解决方案 > MongoDB和Mongo图表:如何计算数组中前一项的增量?

问题描述

我需要能够创建显示连续测量之间差异的可视化。

我将 MongoDB 图表连接到 MongoDB 实例以可视化数据。问题是 AFAIK MongoDB 图表只能显示来自查询或聚合管道的数据。到目前为止,我没有运气在聚合管道中完成以下任务。我开始怀疑我是否为这项工作选择了错误的工具。

我的数据在过滤和排序后看起来像这样:

{
    "run_id": "run_x",
    "measurements": {
        "true_positives": 5,
        "false_positives": 1
    }
},
{
    "run_id": "run_y",
    "measurements": {
        "true_positives": 6,
        "false_positives": 0
    }
}

我需要计算运行之间的增量,以便最终得到:

{
    "run_id": "run_x",
    "measurements": {
        "true_positives": 5,
        "tp_delta": 0
        "false_positives": 1,
        "fp_delta": 0
    }
},
{
    "run_id": "run_y",
    "measurements": {
        "true_positives": 6,
        "tp_delta": 1
        "false_positives": 0,
        "fp_delta": -1
    }
}

我已经能够计算出第一次或最后一次测量的增量,但这还不够。我特别需要连续的增量。用编程语言计算增量当然是微不足道的,但我需要一种将结果提供给 MongoDB Charts 的方法。MapReduce 可以,但我认为它不适用于 MongoDB 图表。由于过滤条件发生变化,将带有增量的中间结果保存到数据库也是不可行的。

有没有办法通过聚合管道实现我所需要的,或者我应该看看其他选项?在这一点上,我非常接近放弃 MongoDB Charts。

标签: mongodbaggregation-frameworkmongodb-charts

解决方案


那么你可以应用一个技巧解决方案。如果我们使用相同的集合并应用正确的运算符,我们可以获得每个文档的上一个/下一个值。

我假设run_id是唯一的,否则我们需要使用_id字段。

伪代码

Given                => 1 2 3 4 5
We order descendant. => 5 4 3 2 1 //It will allow us to get "previous value"    
//Note: If we order ascending, it will allow us to get "next value"

for (var i=0; i<size(collection); i++)
    for (var j=0; j<size(collection); j++)
        // i=0, j=0 5 < 5 - false
        // i=0, j=1 5 < 4 - true
        // i=0, j=2 5 < 3 - true
        // ...
        if (collection[j].run_id < collection[i].run_id)
            next_measure.add(collection[j])
    //for j
    we leave only first item for next_measure
//for i

// Now, we substract measure values
// Order back ascending

db.collection.aggregate([
  {
    $sort: {
      run_id: -1
    }
  },
  {
    $lookup: {
      from: "collection",
      let: {
        prev_value: "$$ROOT"
      },
      pipeline: [
        {
          $sort: {
            run_id: -1
          }
        },
        {
          $match: {
            $expr: {
              $lt: [
                "$run_id",
                "$$prev_value.run_id"
              ]
            }
          }
        },
        {
          $limit: 1
        }
      ],
      as: "next_measure"
    }
  },
  {
    $addFields: {
      tmp: {
        $arrayElemAt: [
          "$next_measure",
          0
        ]
      }
    }
  },
  {
    $project: {
      _id: 0,
      run_id: 1,
      measurements: {
        true_positives: 1,
        tp_delta: {
          $ifNull: [
            {
              $subtract: [
                "$measurements.true_positives",
                "$tmp.measurements.true_positives"
              ]
            },
            0
          ]
        },
        false_positives: 1,
        fp_delta: {
          $ifNull: [
            {
              $subtract: [
                "$measurements.false_positives",
                "$tmp.measurements.false_positives"
              ]
            },
            0
          ]
        }
      }
    }
  },
  {
    $sort: {
      run_id: 1
    }
  }
])

Mongo游乐场


推荐阅读