根据mongodb中的变量按减少的字段分组

时间:2015-10-20 15:19:47

标签: mongodb mongodb-query aggregation-framework

我有以下邮件集合:

{
    "_id" : ObjectId("56214d5632001bae07a6e6b3"),
    "sender_id" : 8,
    "receiver_id" : 2,
    "content" : "fdgfd",
    "state" : 1,
    "timestamp" : 1445023062899.0000000000000000
},
{
    "_id" : ObjectId("56214d5c32001bae07a6e6b4"),
    "sender_id" : 2,
    "receiver_id" : 8,
    "content" : "fasfa",
    "state" : 1,
    "timestamp" : 1445023068443.0000000000000000
},
{
    "_id" : ObjectId("56214d8032001bae07a6e6b5"),
    "sender_id" : 2,
    "receiver_id" : 8,
    "content" : "dfdsfds",
    "state" : 1,
    "timestamp" : 1445023104363.0000000000000000
},
{
    "_id" : ObjectId("56214d8032001bae07a6e6b6"),
    "sender_id" : 2,
    "receiver_id" : 8,
    "content" : "fdsf",
    "state" : 1,
    "timestamp" : 1445023104825.0000000000000000
},
{
    "_id" : ObjectId("56214d8132001bae07a6e6b7"),
    "sender_id" : 2,
    "receiver_id" : 8,
    "content" : "sfsdfs",
    "state" : 1,
    "timestamp" : 1445023105436.0000000000000000
},
{
    "_id" : ObjectId("56214d8132001bae07a6e6b8"),
    "sender_id" : 2,
    "receiver_id" : 8,
    "content" : "f",
    "state" : 1,
    "timestamp" : 1445023105963.0000000000000000
},
{
    "_id" : ObjectId("56214d8432001bae07a6e6b9"),
    "sender_id" : 2,
    "receiver_id" : 8,
    "content" : "qwqwqwq",
    "state" : 1,
    "timestamp" : 1445023108202.0000000000000000
},
{
    "_id" : ObjectId("56214db032001bae07a6e6ba"),
    "sender_id" : 9902,
    "receiver_id" : 2,
    "content" : "fsafa",
    "state" : 1,
    "timestamp" : 1445023152297.0000000000000000
}

我试图获取与用户2一起发送消息的所有唯一用户ID以及最后一条内容消息。所以结果应该是:

[ { user: 8, lastContent: "qwqwqwq" }, { user: 9902, lastContent: "fsafa" } ] 

到目前为止,我有以下代码:

db.getCollection('messenger').group({
keyf: function(doc) {
    return { user: doc.user };
},
cond: {
    $or : [
        { sender_id : 2 },
        { receiver_id : 2 }
    ]
},
reduce: function( curr, result ) {
    result.user = (curr.sender_id == 2 ? curr.receiver_id : curr.sender_id);
    result.content = curr.content;
 },
 initial: { } })

但我只得到最后一个身份证。结果:

{
"0" : {
    "user" : 9902.0000000000000000,
    "content" : "fsafa"
} }

任何人都可以帮我吗?

1 个答案:

答案 0 :(得分:1)

您需要使用.aggregate()方法。您需要使用$match运算符减少管道中文档的大小,该运算符会过滤掉receiver_id不等于2的所有文档。之后,您需要timestampcontent降序排列$sort,这有助于我们获取最后一条消息的sender_id。现在是$group阶段,您可以在其中对文档进行分组,并使用$addToSet运算符返回不同的receiver_id和不同的user_ids数组以及$last运算符最后的消息内容。现在要获得sender_id,我们需要使用$project运算符在$setUnion离子之后得到的receiver_iddb.messenger.aggregate([ { "$match": { "$or": [ { "sender_id": 2 }, { "receiver_id": 2 } ] }}, { "$sort": { "timestamp": 1 } }, { "$group": { "_id": null, "receiver_id": { "$addToSet": { "$receiver_id" } }, "sender_id": { "$addToSet": { "$sender_id" } }, "lastContent": { "$last": "$content" } }}, { "$project": { "_id": 0, "lastContent": 1, "user_ids": { "$setUnion": [ "$sender_id", "$receiver_id" ] } }} ]) 不同的联合。

{ "lastContent" : "fsafa", "user_ids" : [ 9902, 2, 8 ] }

返回:

2

现在,如果你想要的是与用户db.messenger.aggregate([ { "$match": { "$or": [ { "sender_id": 2 }, { "receiver_id": 2 } ] }}, { "$sort": { "timestamp": 1 } }, { "$group": { "_id": { "sender": "$sender_id", "receiver": "$receiver_id" }, "lastContent": { "$last": "$content" }, "timestamp": { "$last": "$timestamp" }, "sender": { "$addToSet": "$sender_id" }, "receiver": { "$addToSet": "$receiver_id" } }}, { "$project": { "_id": 0, "user": { "$setDifference": [ { "$setUnion": [ "$sender", "$receiver" ] }, [ 2 ] ] }, "lastContent": 1, "timestamp": 1 }}, { "$unwind": "$user" }, { "$sort": { "timestamp": 1 } }, { "$group": { "_id": "$user", "lastContent": { "$last": "$lastContent" } } } ]) 的最后一条内容消息不同的用户,那么它就是:

{ "_id" : 9902, "lastContent" : "fsafa" }
{ "_id" : 8, "lastContent" : "qwqwqwq" }

哪个收益率:

/* 
 * Creates the method Collection.reduce(Object, Closure).
 * Unlike Collection.inject(Object, Closure), this method
 * expects a closure with a single argument: the
 * current element in the collection. The closure is
 * re-created to run with the accumulated value as the
 * owner and then called with the current element as the argument.
 */
Collection.metaClass.reduce = { Object initial, Closure closure ->
    delegate.inject(initial) { acc, obj ->
        closure.rehydrate(acc, acc, acc)(obj)
    }
}

def nums = [1, 2, 3]

/*
 * Number.&multiply returns the Number.multiply(Number) method
 * as a Closure.
 */
def result = nums.reduce(1, Number.&multiply) 

assert result == 6