Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.2k views
in Technique[技术] by (71.8m points)

mongodb - Query mongo to detect value changes in time series

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.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

57.0k users

...