Графики MongoDB и Mon go: Как вычислить дельту для предыдущего элемента в массиве? - PullRequest
0 голосов
/ 14 января 2020

Мне нужно иметь возможность создавать визуализации, которые отображают разницу между последовательными измерениями.

У меня есть диаграммы 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. MapReduce будет работать, за исключением того, что я не думаю, что он работает с диаграммами MongoDB. Сохранение промежуточных результатов с дельтами в базу данных также невозможно, поскольку меняются условия фильтрации.

Есть ли способ достичь того, что мне нужно, с помощью конвейеров агрегации или мне следует рассмотреть другие варианты? На данный момент я очень близок к тому, чтобы бросить графики MongoDB.

1 Ответ

0 голосов
/ 15 января 2020

Ну, вы можете применить хитрое решение. Если мы пересекаем одну и ту же коллекцию и применяем правильные операторы, мы можем получить предыдущие / следующие значения для каждого документа.

Я предполагаю, что 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
    }
  }
])

MongoPlayground

...