MongoDB聚合并匹配返回的密钥

时间:2014-08-21 05:08:55

标签: javascript node.js mongodb mongodb-query aggregation-framework

问题是,我正在编写一些代码来从我的数据库中获取用户消息。数据库有 sent_to sent_by 消息键以及我正在关注以获取数据密钥的命令

db.users_messages.aggregate({$group: {_id: {to: "$sent_to", by: "$sent_by"}}})

这将返回所有 sent_to sent_by Users_IDs的列表。现在让我们假设 user1 已将消息发送到 user2 并且 user2 已回复 user1 ,我想要它仅为 user2 返回 user1 ,而不为 user1 返回 user2 。而当我稍后检查这个东西时,我就会留下分页的东西,因为我在聚合上应用了 $ limit 。 希望有人可以帮忙!

1 个答案:

答案 0 :(得分:1)

你所要求的是一个不小的壮举,我认为这里的真正解决方案是在你的文件中加入更多的元数据,特别是以一致的方式表示对话是谁“之间”。

我的意思是,无论是谁发送消息或谁接收,“密钥”都必须是对话的独特之处。考虑这两个基本文件。

{ "from": 1, "to": 2, "between": [1,2] },
{ "from": 2, "to": 1, "between": [1,2] }

在每种情况下,“from”和“to”是每个“用户”的唯一标识符,它们将始终以特定方式排序。 “between”数据总是按照相同的顺序排序,这可以在您创建的代码中完成,也可以通过$sort修饰符和$each的“upsert”功能完成,但重点是保留用于确定哪些文档属于同一分组的“唯一”密钥。

单独使用聚合框架是可能的,但是如果您认为可以在文档中保留它,那么它实际上是不必要的箍跳:

db.converse.aggregate([
    { "$group": {
        "_id": "$_id",
        "from": { "$push": "$from" },
        "to": { "$push": "$to" }  
    }},
    { "$project": {
        "between": { "$setUnion": [ "$from", "$to" ] }
    }},
    { "$unwind": "$between" },
    { "$sort": { "between": 1 } },
    { "$group": {
        "_id": "$_id",
        "between": { "$push": "$between" }
    }},
    { "$group": {
        "_id": "$between",
        "count": { "$sum": 1 }
    }}
])

在早于MongoDB 2.6的版本中,没有类似**$setUnion的版本,可以用不同的方式组合成一个数组:

db.converse.aggregate([
    { "$project": {
        "from": 1,
        "to": 1,
        "type": { "$const": [ "from", "to" ] },
    }},
    { "$unwind": "$type" },
    { "$group": {
        "_id": "$_id",
        "between": {
            "$addToSet": {
                "$cond": [
                    { "$eq": [ "$type", "from" ] },
                    "$from",
                    "$to"
                ]
            }
        }
    }},
    { "$unwind": "$between" },
    { "$sort": { "between": 1 } },
    { "$group": {
        "_id": "$_id",
        "between": { "$push": "$between" }
    }},
    { "$group": {
        "_id": "$between",
        "count": { "$sum": 1 }
    }}
])

在每种情况下,都有合理数量的偏执表现为“不订购套装”。它们可能恰好以这种方式出现,但你可能不能指望它。

这里的原理基本相同,在“between”元素中创建一个唯一排序的“列表”,然后将其用作分组键。从上面的示例文档中,忽略现有的between字段,进程将只返回一个计数为“two”的文档,如下所示:

{ "_id" : [ 1, 2 ], "count" : 2 }

因此,在创建或修改文档时,在文档上维护此类数据确实很有意义。以这种方式,分组变得简单,因为已经识别出“唯一密钥”