Mongoose query for documents from last 24 hours, only one document per hour

风流意气都作罢 提交于 2021-02-10 05:34:08

问题


I am coding an app in which there are some weather sensors that send air's temperature and humidity to the server every 5 minutes.

I would like to draw a chart of how the temperature and humidity change i.e overnight. My idea is to draw the chart basing on data from last 24 hours.

I cannot figure it out by myself, so I thought maybe I could seek help here. Of course, each measurement document has a field called createdAt which has the timestamp of the moment it has been created.

I need to build a mongoose query that will retrieve measurements collected in the last 24 hours, but only take one measurement from each hour. With the 5min time interval with the device's measurements I will have 12 documents created every hour. I would like to retrieve only one of them per each hour.

So far I was able to come up with this (used gt to get the last 24 hours measurements, dont know how to get only one document per each hour):

Measurements.find({ "createdAt": { $gt: new Date(Date.now() - 24*60*60 * 1000) } })


回答1:


Use aggregation

this is a great article for how to group your documents then pick one item per document.

You also need to filter docs for last 24 hours, then project for find and hour from timestamp.

If you need, lets say, last 48 hours, you need to group by hour and day.

Your query will something like this

collection.aggregate([
  {
    "$filter": {
      "createdAt": { $gt: new Date(Date.now() - 24*60*60 * 1000) }
    }
  },
  {
    "$project": {
      "h": {"$hour" : "$createdAt"},
      "original_doc": "$$ROOT"
    }
  },
  {
    "$group": {
      "_id": { "hour": "$h" },
      "docs": { $push: "$original_doc" } 
    }
  },
  { 
    $replaceRoot: {
      newRoot: { $arrayElemAt: ["$docs", 0] }
    }
  }
])



回答2:


You can use below aggregation to get first and last document from each hour.

$sort to order documents by createdAt followed by $group on hour to output first and last document for each hour.

$$ROOT is system variable to access the whole document.

Measurements.aggregate([
  {"$match" : {"createdAt":{"$gt":new Date(Date.now() - 24*60*60 * 1000)}}},
  {"$sort":{"createdAt":-1}},
  {"$group":{
    "_id":{"$hour":"$createdAt"},
    "first":{"$first":"$$ROOT"},
    "last":{"$last":"$$ROOT"}
  }}
])



回答3:


It Works for me:

var pipeline = [
            {
                $match: {
                    $and: [
                        {createdAt: {$gte: startDate}},
                        {createdAt: {$lte: endDate}},
                        {eventType: 'update'}
                    ]
                }
            },
            {$sort: {createdAt: -1}},
            {
                $group: {
                    _id: "$person",
                    persons: {$push: "$$ROOT"}
                }
            },
            {
                $replaceRoot: {
                    newRoot: {$arrayElemAt: ["$persons", 0]}
                }
            },
            {
                $lookup: {
                    from: 'people',
                    localField: 'person',
                    foreignField: '_id',
                    as: 'person'
                }
            },
            {$unwind: "$person"}
        ];

        VisitEvent.aggregate(pipeline)
            .then(function (events) {ere


来源:https://stackoverflow.com/questions/48244163/mongoose-query-for-documents-from-last-24-hours-only-one-document-per-hour

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!