1

我有用户活动的数据库,我想计算活跃用户和他们每个月的活动数量,然后按年对结果进行排序,然后按月对结果进行排序!

我有查询:

query = {
        "activities": {
            "$exists": 1
        },
        "activities.started": {
            "$exists": 1,
            "$type": MONGODB_DATE_TYPE,
            "$gte": datetime(2011, 6, 1),
            "$lte": datetime(2013, 10, 1)
        }
    }

然后,我制作了这样的管道:

pipeline = [
        {'$project': {
            '_id': 1,
            'activities': 1
        }},
        {'$unwind': "$activities"},
        {'$match': query},
        {'$group': {
            '_id': {"y": {"$year": "$activities.started"},
                    "m": {"$month": "$activities.started"}},
            'users': {'$addToSet': "$_id"},
            'activities_count': {"$sum": 1},
        }},
        {"$sort": {
            "_id.y": 1,
            "_id.m": 1,
        }}
    ]

    results = col.aggregate(pipeline)
    results = results.get("result", [])

但是,这个$sort操作效果不好,它没有按_id.y_id.m排序,只有_id.m

我一直在关注mongodb $sort 的这个链接,并且有一个例子表明可以在那里按两个值排序。

所以,我的问题是:我怎样才能先按年订购结果,然后按年按月订购?

编辑

例如,当我把变量和类型函数放在pdb下面时:result

for res in results : print res["_id"]

我得到了这个结果:

{u'y': 2012, u'm': 1}
{u'y': 2013, u'm': 1}
{u'y': 2012, u'm': 2}
{u'y': 2013, u'm': 2}
{u'y': 2012, u'm': 3}
{u'y': 2013, u'm': 3}
{u'y': 2012, u'm': 4}
{u'y': 2013, u'm': 4}
{u'y': 2012, u'm': 5}
{u'y': 2013, u'm': 5}
{u'y': 2011, u'm': 6}
{u'y': 2012, u'm': 6}
{u'y': 2013, u'm': 6}
{u'y': 2011, u'm': 7}
{u'y': 2012, u'm': 7}
{u'y': 2013, u'm': 7}
{u'y': 2011, u'm': 8}
{u'y': 2012, u'm': 8}
{u'y': 2013, u'm': 8}
{u'y': 2011, u'm': 9}
{u'y': 2012, u'm': 9}
{u'y': 2013, u'm': 9}
{u'y': 2011, u'm': 10}
{u'y': 2012, u'm': 10}
{u'y': 2011, u'm': 11}
{u'y': 2012, u'm': 11}
{u'y': 2011, u'm': 12}
{u'y': 2012, u'm': 12}
4

1 回答 1

1

就像评论中提到的@JohnnyHK 一样,python 字典(与 js 对象不同)是无序的。如果你想在 curosr 上使用排序,你会使用类似这样的东西,db.foo.find().sort([("foo", 1), ("bar": 1)]))但聚合不支持这种语法$sort。您可以使用bson.son.SON对象或collections.OrderedDict代替:

from bson.son import SON

pipeline = [
        {'$project': {
            '_id': 1,
            'activities': 1
        }},
        {'$unwind': "$activities"},
        {'$match': query},
        {'$group': {
            '_id': {"y": {"$year": "$activities.started"},
                    "m": {"$month": "$activities.started"}},
            'users': {'$addToSet': "$_id"},
            'activities_count': {"$sum": 1},
        }},
        {"$sort": SON([
            ("_id.y", 1),
            ("_id.m", 1)
        ])}
    ]

编辑

实际上我认为在你的情况下这应该足够了:

pipeline = [
       {'$project': {
           '_id': 1,
           'activities': 1
       }},
       {'$unwind': "$activities"},
       {'$match': query},
       {'$group': {
           '_id': {"y": {"$year": "$activities.started"},
                   "m": {"$month": "$activities.started"}},
           'users': {'$addToSet': "$_id"},
           'activities_count': {"$sum": 1},
       }},
       {"$sort": {"_id": 1}}
   ]

如果排序字段是文档,MonogoDB 似乎逐字段执行排序。文档中字段的顺序可能会在更新期间发生变化,并且在一般情况下它不起作用。然而,这里的字段顺序是在$group阶段中定义的,并且此后不会修改文档,因此这应该不是问题。

按嵌入文档排序 - shell 示例:

> db.bar.insert({foobar: {foo: 2012, bar: 1}})
> db.bar.insert({foobar: {foo: 2012, bar: 5}})
> db.bar.insert({foobar: {foo: 2012, bar: 3}})
> db.bar.insert({foobar: {foo: 2010, bar: 5}})
> db.bar.insert({foobar: {foo: 2010, bar: 1}})
> db.bar.insert({foobar: {foo: 2013, bar: 5}})
> db.bar.insert({foobar: {foo: 2013, bar: 3}})
> db.bar.find({}, {_id: 0}).sort({foobar: 1})
{ "foobar" : { "foo" : 2010, "bar" : 1 } }
{ "foobar" : { "foo" : 2010, "bar" : 5 } }
{ "foobar" : { "foo" : 2012, "bar" : 1 } }
{ "foobar" : { "foo" : 2012, "bar" : 3 } }
{ "foobar" : { "foo" : 2012, "bar" : 5 } }
{ "foobar" : { "foo" : 2013, "bar" : 3 } }
{ "foobar" : { "foo" : 2013, "bar" : 5 } }
于 2013-11-08T21:11:27.297 回答