你没有说你想要年龄的时间单位,但我只是要告诉你如何在几分钟内恢复它,并相信你可以计算出如何将它转换为任何其他时间粒度。我将假设原始文档具有这样的架构:
{ _id: xxx,
post_id: uniqueId,
comments: [ { ..., date: ISODate() }, ..., { ... , date: ISODate() } ],
...
}
现在聚合:
// first you want to define some fixed point in time that you are calculating age from.
// I'm going to use a moment just before "now"
var now = new Date()-1
// unwind the comments array so you can work with individual comments
var unwind = {$unwind:"$comments"};
// calculate a new comment_age value
var project = {$project: {
post_id:1,
comment_age: {
$divide:[
{$subtract:[now, "$comments.date"]},
60000
]
}
} };
// group back by post_id calculating average age of comments
var group = {$group: {
_id: "$post_id",
age: {$avg: "$comment_age"}
} };
// now do the aggregation:
db.coll.aggregate( unwind, project, group )
您可以使用 $max、$min 和其他分组功能来查找最早和最新的评论日期或最低/最高评论年龄。您可以按 post_id 分组,也可以按常量分组以查找整个集合的这些计算,等等。
* 编辑 *
以您为“图书馆书”包含的文档为例,这可能是计算当前“出”的每本书的出书时间的管道,假设“comments.cal_date”是它被检查的时间out 并且所有评论的最新 cal_date 代表当前的“签出”(较旧的已返回):
db.coll.aggregate( [
{ $match : { status : "Out" } },
{ $unwind : "$comments" },
{ $group : { _id : "$_id",
cal_date : { $max : "$comments.cal_date" }
}
},
{ $project : { outDuration : { $divide : [
{ $subtract : [
ISODate("2013-07-15"),
"$cal_date"
]
},
24*60*60*1000
]
}
}
},
{ $group : { _id : 1,
avgOut : { $avg : "$outDuration" }
}
}
] )
步骤在做什么:
- 过滤出基于
status
以计算当前Out
唯一的书籍的文档。
$unwind
展平“评论”数组,以便我们可以
cal_date
使用$group
和查找最新的条目$max
。
- 使用此 max cal_date(表示该书的签出时间)将其从今天的日期中减去,然后将结果除以一天中的毫秒数,即可得出该书已售出的天数
$group
将所有结果加在一起,求出所有已借出图书的平均天数。
* 编辑 *
我假设您了解 Ruby,并且只需要知道如何执行聚合框架命令来计算日期差异/平均值/等。这是 Ruby 中使用“now”来比较 cal_date 的相同代码(您也可以使用常量日期值来执行此操作:
# get db collection from MongoClient into variable 'coll'
# see basic MongoDB Ruby driver tutorial for details
coll.aggregate([
{ "$match" => {"status"=>"Out"} },
{ "$unwind" => "$comments"},
{ "$group" => { "_id" => "$_id", "cal_date" => { "$max" => "$comments.cal_date" } } },
{ "$project"=> {
"outDuration" => {
"$divide" => [
{"$subtract" => [ Time.now, "$cal_date" ] },
24*60*60*1000
]
}
}
},
{ "$group" => {
"_id" => 1,
"avgOut" => {"$avg"=>"$outDuration"}
}
}
])
有关更多示例和说明,请参阅https://github.com/mongodb/mongo-ruby-driver/wiki/Aggregation-Framework-Examples。
如果您想在$group
阶段中保留其他字段,您可以通过更改管道步骤来添加更多字段,如下所示:
{ $group : { _id : "$_id",
barcode : { $first : "$barcode" },
cal_date : { $max : "$comments.cal_date" }
}
}
如果您不需要原件_id
,您可以在第一行(即_id: "$barcode"
)中使用“$barcode”而不是“$_id”,但由于您可能要保留多个字段,$first
trick 可以使用尽可能多的字段你想保留。