Mongodb通过排序和限制进行聚合

时间:2015-09-17 07:29:04

标签: mongodb mongodb-query aggregation-framework

我有一个集合objects

{
    "_id" : ObjectId("55fa65046db58e7d0c8b456a"),
    "object_id" : "1651419",
    "user" : {
        "id" : "65593",
        "cookie" : "9jgkm7ME1HDFD4K6j8WWvg",
    },
    "createddate" : ISODate("2015-09-17T10:00:20.945+03:00")
}

每次用户访问对象的页面时,它都会作为单独的记录存储在集合中。现在我需要获取最后N 访问对象的数组。它应该是 distinct ,因此数组应该有N个唯一记录。此外,它应按createddate排序。 因此,如果用户访问了object_id = 1,那么object_id = 2两次,之后访问object_id = 3并再次访问object_id = 1,数组应该包含:

{
    visits : [1, 3, 2]
}

(与上次访问的时间不同并分类。)

我尝试使用像

这样的结构
db.objects.aggregate([
    {$match: {'user.id' : '65593'}},
    {$sort: { 'createddate':-1 }},
    {$project: {'id': '$user.id', 'obj' : '$object_id'}},
    {$group: {_id:'$id', 'obj': {$addToSet: '$obj'}}},
    {$project:{_id:0, 'obj':'$obj'}}
])

但它会返回未排序的数组,而且我也无法限制数组大小。

2 个答案:

答案 0 :(得分:3)

MongoDB的$addToSet运算符和“集合”通常不以任何方式排序。 Insead,先通过分组获取“不同”值,然后在排序后应用于数组:

db.objects.aggregate([
    { "$match": { "user.id": "65593" } },
    { "$sort": { "user.id": 1, "createddate": -1 } },
    { "$group": {
        "_id": {
            "_id": "$user.id", 
            "object_id": "$object_id"
        },
        "createddate": { "$first": "$createddate" }
    }},
    { "$sort": { "_id._id": 1, "createddate": -1 } },
    { "$group": {
        "_id": "$_id._id",
        "obj": { "$push": "$_id.object_id" }        
    }}
])

因此,如果您希望在$sort之前按日期发现oder,但由于$group不保证任何结果顺序,因此在您与{{{{}}分组之前,您需要再次$sort 3}}构建数组的操作。

请注意,您可能会以某种方式减少“createddate”,因为一般的“distinct”项似乎是“user.id”和“object_id”字段,所以这确实需要某种累加器并且需要包含在您的订购中。

然后数组项将按照您期望的顺序。

如果您需要$limit,则必须处理$unwind并将结果分开限制。在第一组之后交替处理“限制”并在此处进行排序。

但是当然这对于单个主要分组_id来说是唯一可行的,即“user.id”。未来的mongodb版本将支持$slice,这将使多个分组ID更加实用,并且通常会更简单。但是仍然不可能在初始组之前“限制”多个主要groupind id的数组项。

答案 1 :(得分:0)

我找到了我期望的解决方案。

db.objects.aggregate([
  {$match: {'user.id' : '65593'}},
  {$group : { 
      _id : '$object_id',
      dt : {$max: '$createddate'}
      }
  },
  {$sort: {'dt':-1}},
  {$limit:5},
  {$group : { 
      _id :null,
      'objects' : {$push:'$_id'}
      }
  },
  {$project: {_id:0, 'objects':'$objects'}}
])

它返回限制为由createddate向后排序的N个不同数组。 感谢大家的帮助!