2015-11-05 78 views
2

我有一个表示消息线程的模式。因此,在蒙戈数据库中的每个文件看起来像:如何使用聚合来计算特定文档的总和?

{ 
    id: "thread_id", 
    participants: ["user1", "user2"], 
    unReadMessageCounts: [ 
     { 
      participant: "user1", 
      count: 5 
     }, 
     { 
      participant: "user2", 
      count: 3 
     } 
} 

我想要做的就是给定用户的所有未读邮件数的总和 - 说,“用户2”。我知道我可以通过在集合上做一个find()然后编写一个函数来总结给定用户的计数。但是如果可能的话,我想使用mongo的aggregate功能。我知道我可以做一个match来首先选择“user2”是参与者的所有主题,但是如何构建group和/或sum表达式来从文档中拉出正确的字段?

+0

公平点。在我的情况下,开头的文档数量并不是很大,所以@chridam答案略有增加的简洁性使它更适合我。但我也赞成你的回答,因为它确实是一个完美的解决方案。 – rmacqueen

回答

1

使用以下聚合管道来获得所需的结果。初始步骤将输入文档过滤掉仅通过$match运营商接受"user2"参与者。

前面的流水线级,然后“denormalizes”的unReadMessageCounts阵列通过$unwind操作者输出从阵列的每个现任文献2页的文档(在上面的示例数据)。

需要进一步过滤以汇总正确参与者的数据,并且这是通过另一个$match流水线步骤完成的。

使用$group最终聚合操作指定一组的null_id,计算总的计数使用累加器操作者$sum"unReadMessageCounts.count"字段管道中的所有文档。

所以,跑步所给出的样本数据这种聚合管道:

db.collection.aggregate([ 
    { 
     "$match": { "unReadMessageCounts.participant": "user2" } 
    }, 
    { "$unwind" : "$unReadMessageCounts" }, 
    { 
     "$match": { "unReadMessageCounts.participant": "user2" } 
    },  
    { 
     "$group": { 
      "_id": null, 
      "total": { "$sum": "$unReadMessageCounts.count" } 
     } 
    } 
]) 

将产生的结果是:

/* 0 */ 
{ 
    "result" : [ 
     { 
      "_id" : null, 
      "total" : 3 
     } 
    ], 
    "ok" : 1 
} 
+0

虽然这解决了问题,但它不是因为要处理第一个'$ unwind'后要处理的文档的大小而导致的,因为如果您正在处理大集合,这可能是一个非常大的问题。 – styvane

1

可以使用$redact操作如图所示here来限制电流的大小文件要在流水线中处理,然后在$unwind文档中,在$group阶段,使用累加器运算符$sum为“用户2”返回总未读消息。

db.collection.aggregate([ 
    { "$match": { 
     "unReadMessageCounts": { 
      "$elemMatch": { "participant": "user2" } 
     } 
    }}, 
    { "$redact": { 
     "$cond": [ 
      { "$or": [ 
       { "$eq": [ "$participant", "user2" ] }, 
       { "$not" : "$participant" } 
      ]}, 
      "$$DESCEND", 
      "$$PRUNE" 
     ] 
    }}, 
    { "$unwind": "$unReadMessageCounts" }, 
    { "$group": { 
     "_id": null, 
     "total": { "$sum": "$unReadMessageCounts.count" } 
    }} 
]) 
相关问题