Alex S.
Alex S.

Reputation: 355

MongoDB aggregations. Get value differences

I've been struggling with mongo trying to find a solution to show the differences between values.

I have values like this:

[
    {val: 1},
    {val: 4},
    {val: 7},
    {val: 8},
    {val: 11}
]

And I want to receive something like this:

[
    {diff: 3},
    {diff: 3},
    {diff: 1},
    {diff: 3}
]

Every value is evaluated by taking the next one (4) and subtracting the previous one (1). After all this, we receive 3 in output, which is located in the second list as the first item.

Is it possible to achieve it using MongoDB aggregations?

Upvotes: 2

Views: 56

Answers (1)

Valijon
Valijon

Reputation: 13103

You need to group them into array, calculate diff and flatten again.

Pseudocode

//We $group here all values
var _data = [{val: 1}, {val: 4}, ..., {val: 11}]; 
//With $range operator we get nº of items
// We ensure even items, since odd items will return null as last item
var idx  = [0, 1, 2, ..., n]; 
//Here we store diff items with $map operator
var data  = []; 
//$map
for (var i in idx) {
   data[i] = _data[i+1] - _data[i];
}
//$unwind
{data:[0]}, {data[1]}, {data[2]}, ...
//$replaceRoot
{                   
  data:{            {
    diff : 3   -->    diff : 3 
  }                 }
}                   

Add these steps into your pipeline:

db.collection.aggregate([
  {
    $group: {
      _id: null,
      data: { $push: "$$ROOT" }
    }
  },
  {
    $addFields: {
      data: {
        $map: {
          input: {
            $range: [
              0,
              {
                $subtract: [
                  { $size: "$data" },
                  { $mod: [ { $size: "$data" }, 2 ] }
                ]
              },
              1
            ]
          },
          as: "idx",
          in: {
            diff: {
              $subtract: [
                {
                  $arrayElemAt: [
                    "$data.val",
                    {
                      $add: [ "$$idx", 1 ]
                    }
                  ]
                },
                {
                  $arrayElemAt: [ "$data.val", "$$idx" ]
                }
              ]
            }
          }
        }
      }
    }
  },
  {
    $unwind: "$data"
  },
  {
    $replaceRoot: {
      newRoot: "$data"
    }
  }
])

MongoPlayground

Upvotes: 1

Related Questions