MongoDB按分组查询

4

我该如何在Mongodb中查询一个位置的进出次数并按用户分组。上述集合有多个位置,用户可以进入或离开。

{ "ActivityList" : [ 
{ "type" : "entry",
  "timestamp" : Date( 1344473257320 ),
  "user" : { "$ref" : "userProfile",
    "$id" : ObjectId( "4fdeaf6fde26fd298262bb81" ) } }, 
  { "type" : "exit",
  "timestamp" : Date( 1348792321111 ),
  "user" : { "$ref" : "userProfile",
    "$id" : ObjectId( "4fdeaf6fde26fd298262bb81" ) } }, 
{ "type" : "entry",
  "timestamp" : Date( 1348881701129 ),
  "user" : { "$ref" : "userProfile",
    "$id" : ObjectId( "4fdeaf6fde26fd298262bb81" ) } }, 
{ "type" : "exit",
  "timestamp" : Date( 1348942808700 ),
  "user" : { "$ref" : "userProfile",
    "$id" : ObjectId( "4fdeaf6fde26fd298262bb81" ) } }, 
{ "type" : "entry",
  "timestamp" : Date( 1348957400052 ),
  "user" : { "$ref" : "userProfile",
    "$id" : ObjectId( "4fdeaf6fde26fd298262bb81" ) } }, 
{ "type" : "exit",
  "timestamp" : Date( 1349024290729 ),
  "user" : { "$ref" : "userProfile",
    "$id" : ObjectId( "4fdeaf6fde26fd298262bb81" ) } } ],
"Loc" : { "$ref" : "location",
      "$id" : ObjectId( "501cb6d4e7e9a8f958f903c5" ) },
 "_id" : ObjectId( "502308a9e7e91ab176f6708e" ) }

我正在尝试类似这样的操作,但没有成功,请参考这里
select a,b,sum(c) csum from coll where active=1 group by a,b



db.coll.group(
       {key: { a:true, b:true },
        cond: { active:1 },
        reduce: function(obj,prev) { prev.csum += obj.c; },
        initial: { csum: 0 }
        });

MongoDB的新功能 ------------> v2.2 - user956584
你能展示一下你尝试过但没有成功的代码吗? - JohnnyHK
1个回答

5
您正在使用的文档结构(项目数组)需要在 $group() 函数中进行一些操作,这些操作可以更轻松地使用 MongoDB 2.2 中的 MapReduce 或新的 聚合框架 进行操作。
下面是使用聚合框架的示例:
db.activity.aggregate(

    // Find matching documents first (can take advantage of index)
    { $match : {
        Loc: DBRef("location", ObjectId("501cb6d4e7e9a8f958f903c5"))
    }},

    // Unwind the ActivityList array as a document stream
    { $unwind : "$ActivityList" },

    // Group the stream by activity types for a user
    { $group : {
        _id : "$ActivityList.user",
        activity: { $push: "$ActivityList.type" } 
    }},

    // Unwind the activity types so they can be counted
    { $unwind : "$activity" },

    // Final grouping: count of action (entry or exit) for each user
    { $group : {
        _id : { user: "$_id", action: "$activity" },
        count: { $sum: 1 }
    }}
)

这将产生类似于以下结果:

{
    "result" : [
        {
            "_id" : {
                "user" : DBRef("userProfile", ObjectId("4fdeaf6fde26fd298262bb81")),
                "action" : "exit"
            },
            "count" : 6
        },
        {
            "_id" : {
                "user" : DBRef("userProfile", ObjectId("4fdeaf6fde26fd298262bb81")),
                "action" : "entry"
            },
            "count" : 3
        },
        {
            "_id" : {
                "user" : DBRef("userProfile", ObjectId("4fdeaf6fde26fd298262bb82")),
                "action" : "entry"
            },
            "count" : 2
        },
        {
            "_id" : {
                "user" : DBRef("userProfile", ObjectId("4fdeaf6fde26fd298262bb85")),
                "action" : "entry"
            },
            "count" : 1
        }
    ],
    "ok" : 1
}

3
不是恶意挑衅,但这比MySQL更容易使用吗?每个MongoDB的支持者都告诉我它比MySQL更易于使用。 - ajacian81
2
@ajacian81 相对于 MySQL(和其他 SQL 数据库),MongoDB 更容易扩展,但编写查询语句并不一定比其他数据库更容易或更难。使用 MapReduce/聚合的某些查询比相应的 SQL 查询更容易编写,而有些则更难。对于基本的 SELECT、INSERT、UPDATE,我认为在编写这些查询方面,MongoDB 与 SQL 差不多难度相当。 - wprl
@Stennie:如何在JavaScript中迭代相同的结果? - Workonphp
2
@Workonphp:在MongoDB 2.2/2.4中,聚合结果以result数组的形式内联返回到响应文档中。如果您想在JavaScript中迭代该数组,可以使用array.forEach,例如:db.collection.aggregate(...).result.forEach(function(doc) { printjson(doc) }),其中printjson()是您想要对每个结果文档执行的操作。值得注意的是,在即将发布的MongoDB 2.6版本(或dev/unstable 2.5版本)中,聚合命令将默认提供基于游标的迭代器,类似于普通的find()。 - Stennie

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接