我每小时都会向架构添加一个条目,以便跟踪当天的增长情况,同时保持当前的当前分数。现在我希望能够提取过去一周每天的最新记录。结果将是6个记录,在午夜或午夜左右,前6天,第7个记录是当天的最新记录。
这是我的架构:
var schema = new Schema({
aid: { type: Number }
, name: { type: String }
, score: { type: Number }
, createdAt: { type: Date, default: Date.now() }
})
修改
我已尝试使用此静态,但它会将完全相同的记录拉出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)
})
}
}
如果我使用的是SQL,我会选择MAXDATE进行子查询并将其连接到我的主查询,以便检索我想要的结果。无论如何要在这里做到这一点?
答案 0 :(得分:6)
假设我们有一个跟踪股票价格的网站。每隔几个 分钟从上午10点到下午4点,它获得了股票的最新价格, 它存储在MongoDB中。现在,作为报告应用程序的一部分, 我们想找到过去30天的收盘价。这可以 使用小组轻松完成。
我对Mongoose并不熟悉,但是我试图让她的例子适应你的情况。注意我将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()
);
答案 1 :(得分:1)
解决方案是使用group()按天分组记录。它很花哨,很慢并且可以阻塞(意味着没有其他东西可以同时运行),但如果你的记录集不是太大,它就会非常强大。
组:http://www.mongodb.org/display/DOCS/Aggregation#Aggregation-Group
至于mongoose,我不确定它是否直接支持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
})
}
我的博客中的群组和地图之间的更多比较减少了: http://j-query.blogspot.com/2011/06/mongodb-performance-group-vs-find-vs.html
本机驱动程序中没有关于group命令的文档,因此您必须在此处查看源代码: https://github.com/christkv/node-mongodb-native/blob/master/lib/mongodb/collection.js
另外,对于排序,请检查https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Array/sort以获取确切的语法
编辑:更好的主意!!!
只需要一个名为“lastRequestOfDay”的特殊集合,然后将_id作为日期。 使用每个新请求覆盖该值。查询和快速写入将非常容易,并且每天都会写出最后一个值!
答案 2 :(得分:0)
将另一个属性添加到名为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)
}
答案 3 :(得分:0)
尝试这样的事情:
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);
}
}
答案 4 :(得分:0)
似乎没有人试图“接近午夜”。 :)我在原始代码中看到的问题是它检查了大于或等于x天前的时间...这将始终返回最近的时间。我很困惑为什么DeaDEnD的解决方案会返回相同的记录7次。此外,您从未致电fn
,但这不是您最关心的问题,是吗?
尝试添加.lt(now - (now % oneday) - (i - 1) * oneday)
(假设为0索引;如果是1索引,则将其更改为i - 2
)