简体   繁体   English

查找过去7天的当天的最后一份文件

[英]Find last document of the day for the last 7 days

I am adding entries to a schema every hour in order to track growth over the course of days while maintaining a current score for the current day. 我每小时都会在架构中添加条目,以便跟踪几天内的增长情况,同时保持当前一天的当前得分。 Now I would like to be able to pull the most recent record for each day for the past week. 现在,我希望能够获取过去一周每天的最新记录。 The results would be 6 records at or around midnight for 6 days previous and the 7th being the latest for the current day. 结果将是前6天午夜或前后的6条记录,而第7条是当天的最新记录。

Here is my schema: 这是我的架构:

var schema = new Schema({
  aid: { type: Number }
, name: { type: String }
, score: { type: Number }
, createdAt: { type: Date, default: Date.now() }
})

Edit 编辑

I've tried using this static, but it pulls the exact same record 7 times 我试过使用此静态,但它提取相同的记录7次

schema.statics.getLastWeek = function(name, fn) {
  var oneday = 60 * 60 * 24
    , now = Date.now()
    , docs = []

  for (var i = 1; i <= 7; i++) {
    this.where('name', new RegExp(name, 'i'))
    .where('createdAt')
    .gte(now - (i * oneday))
    .desc('createdAt')
    .findOne(function(err,doc){
      docs.push(doc)
    })
  }
}

If I were using SQL I would do a subquery selecting MAXDATE and join it to my main query in order to retrieve the results I want. 如果我使用的是SQL,我将选择MAXDATE进行子查询,并将其加入我的主查询中,以检索所需的结果。 Anyway to do this here? 无论如何要在这里做?

Kristina Chodorow gives a detailed recipe for this exact task in her book MongoDB: The Definitive Guide : 克里斯蒂娜(Kristina Chodorow)在她的《 MongoDB:权威指南 》( MongoDB:The Definitive Guide)一书中详细介绍了该任务的详细配方

Suppose we have a site that keeps track of stock prices. 假设我们有一个跟踪股价的站点。 Every few minutes from 10 am to 4 pm, it gets the latest price for a stock, which it stores in MongoDB. 从上午10点到下午4点每隔几分钟,它将获取最新的股票价格,并将其存储在MongoDB中。 Now, as part of a reporting application, we want to find the closing price for the past 30 days. 现在,作为报表应用程序的一部分,我们希望找到过去30天的收盘价。 This can be easily accomplished using group. 使用组可以很容易地做到这一点。

I'm not familiar with Mongoose, however I've tried to adapt her example to your case below. 我对猫鼬不熟悉,但是我尝试将她的示例调整为适合您的以下情况。 Note I changed the createdAt default property from a value to a function and added an extra field datestamp to your schema: 注意,我将createdAt default属性从一个值更改为一个函数,并向您的模式添加了一个额外的字段datestamp

var oneday = 24 * 60 * 60;

var schema = new Schema({
  aid: { type: Number }
, name: { type: String }
, score: { type: Number }

  // default: is a function and called every time; not a one-time value!
, createdAt: { type: Date, default: Date.now }

  // For grouping by day; documents created on same day should have same value
, datestamp: { type: Number
             , default: function () { return Math.floor(Date.now() / oneday); }
             }
});


schema.statics.getLastWeek = function(name, fn) {
    var oneweekago = Date.now() - (7 * oneday);

    ret = this.collection.group({
          // Group by this key. One document per unique datestamp is returned.
          key: "datestamp"
          // Seed document for each group in result array.
        , initial: { "createdAt": 0 }
          // Update seed document if more recent document found.
        , reduce: function(doc, prev) {
              if (doc.createdAt > prev.createdAt) {
                prev.createdAt = doc.createdAt;
                prev.score = doc.score;

                // Add other fields, if desired:
                prev.name = doc.name;
              }
          // Process only documents created within past seven days
        , condition: { "createdAt" : {"$gt": oneweekago} }
        }});

   return ret.retval;

   // Note ret, the result of group() has other useful fields like:
   // total "count" of documents,
   // number of unique "keys",
   // and "ok" is false if a problem occurred during group()

);

A solution is to use group() to groups records by day. 一种解决方案是使用group()按天对记录进行分组。 It's fancy, slow and can be blocking (meaning nothing else can run at the same time), but if your record set isn't too huge it's pretty powerful. 它花哨,缓慢且可能会阻塞(意味着其他任何东西都无法同时运行),但是如果您的记录集不是太大,那么它就非常强大。

Group: http://www.mongodb.org/display/DOCS/Aggregation#Aggregation-Group 组: http : //www.mongodb.org/display/DOCS/Aggregation#Aggregation-Group

As for mongoose, I'm not sure if it supports group() directly, but you can use the node-mongodb-native implementation, by doing something like this (pseudo-code, mostly): 至于猫鼬,我不确定它是否直接支持group(),但是您可以通过执行以下操作(主要是伪代码)来使用node-mongodb-native实现:

schema.statics.getLastWeek = function(name, cb) {
    var keys = {} // can't remember what this is for
    var condition = {} // maybe restrict to last 7 days
    var initial = {day1:[],day2:[],day3:[],day4:[],day5:[],day6:[],day7:[]}
    var reduce = function(obj, prev) {
        // prev is basically the same as initial (except with whatever is added)
        var day = obj.date.slice(0,-10) // figure out day, however it works
        prev["day" + day].push(obj) // create grouped arrays
        // you could also do something here to sort by _id
        // which is probably also going to get you the latest for that day 
        // and use it to replace the last item in the prev["day" + 1] array if
        // it's > that the previous _id, which could simplify things later
    }
    this.collection.group(keys, condition, initial, reduce, function(err, results) {
      // console.log(results) 
      var days = results // it may be a property, can't remember
      var lastDays = {}
      days.forEach(function(day) {
          // sort each day array and grab last element

          lastDays[day] = days[day].sort(function(a, b) {
            return a.date - b.date // check sort syntax, you may need a diff sort function  if it's a string
          }).slice(-1) // i think that will give you the last one
      })
      cb(lastDays) // your stuff
    })
}

Some more comparisons between groups and map reduce from my blog: http://j-query.blogspot.com/2011/06/mongodb-performance-group-vs-find-vs.html 群组和地图之间的其他一些比较从我的博客中减少了: http : //j-query.blogspot.com/2011/06/mongodb-performance-group-vs-find-vs.html

There are no docs about the group command in the native driver, so you'll have to peer through the source code here: https://github.com/christkv/node-mongodb-native/blob/master/lib/mongodb/collection.js 本机驱动程序中没有有关group命令的文档,因此您必须在此处浏览源代码: https : //github.com/christkv/node-mongodb-native/blob/master/lib/mongodb/ collection.js

Also for sort, check check https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/sort for exact syntax 同样要进行排序,请检查https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/sort以获取确切的语法

Edit: Better Idea!!! 编辑:更好的主意!

Just have a special collection called "lastRequestOfDay" and make the _id the day. 只需有一个名为“ lastRequestOfDay”的特殊集合,并将_id设置为当天即可。 Overwrite the value with each new request. 用每个新请求覆盖值。 It will be super easy to query and fast to write and will always have the last value written each day! 这将是超级容易查询和快速编写的方法,并且总是每天都有最后写入的值!

Add another property to the schema named dateAdded or something. 将另一个属性添加到名为dateAdded的架构中。

schema.statics.getLastWeek = function(name, fn) {
var oneday = 60 * 60 * 24
  , now = Date.now()
  , docs = []

for (var i = 0; i < 7; i++) {
  this.where('name', new RegExp(name, 'i'))
  .where('createdAt')
  .lt(now - (i * oneday))
  .gte(now - ((i + 1) * oneday))
  .desc('createdAt')
  .findOne(function(err,doc){
    // might not always find one
    docs.push(doc)
  })
}
return fn(null, docs)
}

Try something like this: 尝试这样的事情:

schema.statics.getLastWeek = function(name, fn) {
  var oneday = 60 * 60 * 24
    , now = Date.now()
    , docs = []
   , that = this

  function getDay(day){
     that.where('name', new RegExp(name, 'i'))
     .where('createdAt')
     .gte(now - (day * oneday))
     .desc('createdAt')
     .findOne(function(err,doc){
     docs.push(doc)
    })

  }

  for (var i = 1; i <= 7; i++) {
    getDay(i);
  }
}

Nobody seems to be trying for "close to midnight". 似乎没人试图“接近午夜”。 :) The issue I saw with the original code was that it checked for a time greater than or equal to x days ago... which will always return the most recent time. :)我在原始代码中看到的问题是它检查的时间大于或等于x天前……这将始终返回最近的时间。 I'm confused as to why DeaDEnD's solution returns the same record 7 times, though. 我对为什么DeaDEnD的解决方案会返回7次相同的记录感到困惑。 Also, you never called fn , but that's not really the biggest of your concerns, is it? 另外,您从未致电过fn ,但这并不是您最担心的问题,不是吗?

Try adding on .lt(now - (now % oneday) - (i - 1) * oneday) (assuming 0-indexed; if it's 1-indexed, change that to say i - 2 ) 尝试添加.lt(now - (now % oneday) - (i - 1) * oneday) (假设0索引;如果是1索引,则改成i - 2

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM