Query mongo to detect value changes in time series

2020-02-15 06:03发布

Im wondering if the following is possible in MongoDB.

I have collection of documents that represent changes in some value in time:

{
  "day" : ISODate("2018-12-31T23:00:00.000Z"),
  "value": [some integer value]
}

There are no 'holes' in the data, I have entries for all days within some period.

Is it possible to query this collection to get only documents that has different value than previous one (when sorting by day asc)? For example, having following documents:

{
      "day" : ISODate("2019-04-01T00:00:00.000Z"),
      "value": 10
},
{
      "day" : ISODate("2019-04-02T00:00:00.000Z"),
      "value": 10
},
{
      "day" : ISODate("2019-04-03T00:00:00.000Z"),
      "value": 15
},
{
      "day" : ISODate("2019-04-04T00:00:00.000Z"),
      "value": 15
},
{
      "day" : ISODate("2019-04-05T00:00:00.000Z"),
      "value": 15
},
{
      "day" : ISODate("2019-04-06T00:00:00.000Z"),
      "value": 10
}

I want to retrieve documents for 2018-04-01, 2018-04-03 and 2018-04-06.

Im posting this question again because previous one was wrongly marked as duplicate.

1条回答
趁早两清
2楼-- · 2020-02-15 06:34

You need to get pairs of consecutive docs to detect the gap. For that you can push all documents into single array, and zip it with itself shifted 1 element from the head:

db.collection.aggregate([
    { $sort: { day: 1 } },
    { $group: { _id: null, docs: { $push: "$$ROOT" } } },
    { $project: {
        pair: { $zip: {
            inputs:[ { $concatArrays: [ [false], "$docs" ] }, "$docs" ]            
        } }
    } },
    { $unwind: "$pair" },
    { $project: {
        prev: { $arrayElemAt: [ "$pair", 0 ] },
        next: { $arrayElemAt: [ "$pair", 1 ] }
    } },
    { $match: {
         $expr: { $ne: ["$prev.value", "$next.value"] } 
    } },
    { $replaceRoot:{ newRoot: "$next" } }
])

The rest is trivial - you unwind the array back to documents, compare the pairs, filter out the equal ones, and replaceRoot from what's left.

查看更多
登录 后发表回答