我有一个包含子文档的文档,看起来像是:
{
"name" : "some name1"
"like" : [
{ "date" : ISODate("2012-11-30T19:00:00Z") },
{ "date" : ISODate("2012-12-02T19:00:00Z") },
{ "date" : ISODate("2012-12-01T19:00:00Z") },
{ "date" : ISODate("2012-12-03T19:00:00Z") }
]
}
是否可以获取“最喜欢”的文档(过去7天的平均值)并按计数排序?
答案 0 :(得分:8)
有几种不同的方法可以解决这个问题。我将关注的解决方案使用mongodb的聚合框架。首先,这是一个解决您的问题的聚合管道,它将是对命令中发生的事情的解释/细分。
db.testagg.aggregate(
{ $unwind : '$likes' },
{ $group : { _id : '$_id', numlikes : { $sum : 1 }}},
{ $sort : { 'numlikes' : 1}})
此管道有3个主要命令:
1)展开:这会拆分'赞'字段,以便每个文档有1'喜欢'元素
2)组:使用_id字段重新组合文档,为其找到的每个文档递增numLikes字段。这将导致numLikes填充一个数字,该数字等于
之前“喜欢”中的元素数量3)排序:最后,我们根据numLikes按升序对返回值进行排序。在测试中,我运行此命令的输出是:
{"result" : [
{
"_id" : 1,
"numlikes" : 1
},
{
"_id" : 2,
"numlikes" : 2
},
{
"_id" : 3,
"numlikes" : 3
},
{
"_id" : 4,
"numlikes" : 4
}....
这是通过以下方式插入的数据:
for (var i=0; i < 100; i++) {
db.testagg.insert({_id : i})
for (var j=0; j < i; j++) {
db.testagg.update({_id : i}, {'$push' : {'likes' : j}})
}
}
请注意,这并不能完全回答您的问题,因为它避免了选择日期范围的问题,但它应该有助于您开始并朝着正确的方向前进。
当然,还有其他方法可以解决这个问题。一种解决方案可能是在客户端进行所有排序和操作。这只是获取所需信息的一种方法。
编辑:如果你发现这有点单调乏味,那么就有一张将$ size运算符添加到聚合框架的票证,我邀请你观看并可能对它进行投票,如果你感兴趣的话,可以尝试加速添加这个新的运算符
答案 1 :(得分:8)
更好的解决方案是保留一个计数字段,该字段将记录此文档的喜欢次数。虽然您可以使用聚合来执行此操作,但性能可能不会很好。在count字段上有一个索引会使读操作变得很快,你可以在插入新的时候使用原子操作来递增计数器。
答案 2 :(得分:1)
您可以使用以下方法从mongodb v3.4开始简化以上聚合查询:
> db.test.aggregate([
{ $unwind: "$like" },
{ $sortByCount: "$_id" }
]).pretty()
{ "_id" : ObjectId("5864edbfa4d3847e80147698"), "count" : 4 }
同样正如@ACE所说,您现在可以在投影中使用$ size:
db.test.aggregate([
{ $project: { count: { $size : "$like" } } }
]);
{ "_id" : ObjectId("5864edbfa4d3847e80147698"), "count" : 4 }