【问题标题】:MongoDB aggregate and match the returned keysMongoDB 聚合并匹配返回的键
【发布时间】:2014-10-14 15:08:44
【问题描述】:

问题是,我正在编写一些代码来从我的数据库中获取用户消息。 DB 有 sent_tosent_bymessage 键,我要获取数据键的命令是

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

这将返回所有 sent_tosent_by 用户 ID 的列表。现在让我们假设如果 user1 已将消息发送给 user2 并且 user2 已回复 user1,我想要它只为 user2 返回 user1,而不为 user1 返回 user2。当我稍后检查这个东西时,我就剩下分页了,因为我在聚合上应用了 $limit 。 希望有人能帮忙!

【问题讨论】:

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


    【解决方案1】:

    您要问的是不小的壮举,我认为这里真正的解决方案是在您的文档中包含更多元数据,特别是以一致的方式表示“之间”的对话是谁。

    我的意思是,无论是谁发送消息或接收消息,“密钥”对于对话都必须是唯一的。考虑这两个基本文档。

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

    在每种情况下,“from”和“to”都是每个“用户”的唯一标识符,它们总是以特定方式排序。 “中间”数据始终按相同顺序排序,这可以在您创建时在代码中完成,也可以通过带有$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 字段,该过程将只返回一个计数为“二”的文档,如下所示:

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

    因此,在创建或修改文档时维护此类数据确实很有意义。这样分组就变得简单了,因为“唯一键”已经被识别了

    【讨论】:

    • 我喜欢你的建议,但似乎还有很长的路要走。
    • @Ravi 很长的路要走?我认为聚合是“漫长的道路”。如果这是您打算做的事情,那么您最好维护文档中的数据。聚合表明它是“可能的”,而不是您“应该”这样做。您“应该”在文档中包含该信息,而不是每次都投影它。
    • 既然你在这里,还有一个问题,在添加类似 { "from": 2, "to": 1, "between": [1,2] }{ "from": 2, "to": 1, "between": [1,3] } 这样的东西之后,有没有一种方法可以在字段之间调用 distinct 来获得整个单独的数组,而不是全部不同的项目(比如当我在这个字段上调用 ​​distinct 它返回数组:[1,2,3])?
    • 别介意,我得到了最后一个的答案。谢谢你的时间:)
    猜你喜欢
    • 2021-07-28
    • 2018-06-13
    • 2016-05-20
    • 2015-08-09
    • 1970-01-01
    • 2020-06-24
    • 1970-01-01
    • 2020-06-29
    • 2019-01-24
    相关资源
    最近更新 更多