根据上次更新,这似乎在正确的轨道上,但我可能会为设计提供几个“tweeks”,并解决问题的日期范围部分。
虽然您可以使用 mongoose 对 populate 做一些好事,但仍然值得记住的是,这种“加入”只是模拟的,因为实际发生的是按顺序对数据库进行额外查询检索“相关”项目。
因此,在使用 MongoDB 时,最好将要使用的信息保存在同一个集合中。因此,对于这里的简单示例,我将在这些“事件”类型的条目中保留“用户名”。我这样做是因为这是总结时将使用的信息。因此,“事件”(我称之为它们)的文档看起来像这样:
{
"userId": 123,
"username": "user1",
"type": "q",
"time": ISODate("2014-04-07T03:56:33.488Z")
},
{
"userId": 123,
"username": "user1",
"type": "p",
"time": ISODate("2014-04-07T03:56:33.488Z")
},
{
"userId": 456,
"username": "user2",
"type": "p",
"time": ISODate("2014-04-07T03:56:33.488Z")
}
当然还有其他字段,但我们将重点关注这些字段。
要将这些在一个日期范围内组合在一起,您可以执行以下操作:
db.events.aggregate([
// Match the date range required
{ "$match": {
"time": {
"$gte": new Date("2014-04-07"),
"$lt": new Date("2014-04-14")
}
}},
// Group and Reshape the matching documents
{ "$group": {
"_id": "$userId",
"username": { "$first": "$username" },
"q" : { "$sum": { "$eq": [ "$type", "q" ] } },
"p" : { "$sum": { "$eq": [ "$type", "p" ] } },
"l" : { "$sum": { "$eq": [ "$type", "l" ] } }
}},
// Project to get a "score" value
{ "$project": {
"username": 1,
"p": 1,
"q": 1,
"l": 1,
"score": { "$add": [
"$q",
{ "$cond": [
"$p",
{ "$divide": [ "$p", 10 ] },
0
]},
{ "$cond": [
"$l",
{ "$divide": [ "$l", 10 ] },
0
]},
]}
}},
// Sort the results by the "score" descending
{ "$sort": { "score": -1 } },
// Optionally limit the results
{ "$limit": 10 }
])
因此,所有这些都将时间段内基于“事件”的条目中每个用户的结果分组,计算总分(注意不要除以 0),然后对结果进行排序,使最高分排在首位.
您甚至可以执行类似的查询来查找每周或其他时间间隔中排名最高的用户:
db.events.aggregate([
// Match the date range required - one year as a sample
{ "$match": {
"time": {
"$gte": new Date("2014-01-01"),
"$lt": new Date("2015-01-01")
}
}},
// Group and Reshape the matching documents
{ "$group": {
"_id": {
"week": { "$week": "$time" },
"userId": "$userId"
},
"username": { "$first": "$username" },
"q" : { "$sum": { "$eq": [ "$type", "q" ] } },
"p" : { "$sum": { "$eq": [ "$type", "p" ] } },
"l" : { "$sum": { "$eq": [ "$type", "l" ] } }
}},
// Project to get a "score" value
{ "$project": {
"username": 1,
"p": 1,
"q": 1,
"l": 1,
"score": { "$add": [
"$q",
{ "$cond": [
"$p",
{ "$divide": [ "$p", 10 ] },
0
]},
{ "$cond": [
"$l",
{ "$divide": [ "$l", 10 ] },
0
]},
]}
}},
// Sort by highest score for each week
{ "$sort": { "_id.week": 1, "score": -1 } },
// Group again to get the highest value in each week
{ "$group": {
"_id": "$_id.week",
"userId": { "$first": "$_id.userId" },
"username": { "$first": "$username" },
"q": { "$first": "$q" },
"p": { "$first": "$p" },
"l": { "$first": "$l" },
"score": { "$first": "$score" },
}}
])
如果您需要运行总计,那么您最好将这些结果“预先汇总”到另一个集合中,并在整体性能方面保持谨慎的几周,或者甚至确实按周或任何最适合您的时间范围来保持运行总计.
因此,作为参考,这里有一些内容可以参考,但可以查看各种 aggregation framework operators 的主要文档,尤其是 Date aggregation operators,因为它们可以让您在不同组件上“组合”在一起日期,可以是周、月、日、小时或年。