【问题标题】:MongoDB: Find document given field values in an object with an unknown keyMongoDB:在具有未知键的对象中查找给定字段值的文档
【发布时间】:2016-04-03 21:40:21
【问题描述】:

我正在建立一个关于论文/论点的数据库。它们与其他参数相关,我已将它们放在一个带有dynamic key 的对象中,这是完全随机的。

{
    _id : "aeokejXMwGKvWzF5L",
    text : "test",
    relations : {
        cF6iKAkDJg5eQGsgb : {
            type : "interpretation",
            originId : "uFEjssN2RgcrgiTjh",
            ratings: [...]
         }
    }
}

如果我只知道type的值,我能找到这个文件吗?那就是我想做这样的事情:

db.theses.find({relations['anything']: { type: "interpretation"}}})

如果relations 是一个数组,这可以使用positional operator 轻松完成。但是后来我无法更改 ratings 中的对象,因为 mongo doesn't support 那些更新。我在这里询问是否可以避免更改数据库结构。

【问题讨论】:

    标签: mongodb mongodb-query


    【解决方案1】:

    虽然由于使用嵌套数组时的更新问题,您似乎已经接近了这种结构,但您确实只是通过执行其他不受支持的操作而引起了另一个问题,那就是没有 "通配符” 使用最佳标准查询运算符搜索未指定键的概念。

    真正搜索此类数据的唯一方法是使用服务器上的 JavaScript 代码使用 $where 遍历键。这显然不是一个真正的好主意,因为它需要蛮力评估,而不是使用索引等有用的东西,但可以按如下方式处理:

    db.theses.find(function() {
        var relations = this.relations;
        return Object.keys(relations).some(function(rel) {
            return relations[rel].type == "interpretation";
        });
    ))
    

    虽然这将从集合中返回那些包含所需嵌套值的对象,但它必须检查集合中的每个对象才能进行评估。这就是为什么只有在与可以直接使用索引而不是作为集合中对象的硬值的东西配对时才应该使用这种评估。

    更好的解决方案是考虑重构数据以利用搜索中的索引。如果需要更新“评级”信息,则基本上“展平”结构以将每个“评级”元素视为唯一的数组数据:

    {
        "_id": "aeokejXMwGKvWzF5L",
        "text": "test",
        "relationsRatings": [
            {
                "relationId": "cF6iKAkDJg5eQGsgb",
                "type": "interpretation",
                "originId": "uFEjssN2RgcrgiTjh",
                "ratingId": 1,
                "ratingScore": 5
            },
            {
                "relationId": "cF6iKAkDJg5eQGsgb",
                "type": "interpretation",
                "originId": "uFEjssN2RgcrgiTjh",
                "ratingId": 2,
                "ratingScore": 6
            }
       ]
    }
    

    现在搜索当然很简单:

    db.theses.find({ "relationsRatings.type": "interpretation" })
    

    当然,positional $ 运算符现在可以与更扁平的结构一起使用:

    db.theses.update(
        { "relationsRatings.ratingId": 1 },
        { "$set": { "relationsRatings.$.ratingScore": 7 } }
    )
    

    当然,这意味着为每个“评分”值复制“相关”数据,但这通常是按匹配位置更新的成本,因为这仅支持单级数组嵌套。

    因此,您可以强制逻辑与您的结构方式相匹配,但这样做并不是一个好主意,并且会导致性能问题。但是,如果您在这里的主要需求是更新“评分”信息,而不是仅仅附加到内部列表,那么更扁平的结构将有更大的好处,当然搜索速度也会更快。

    【讨论】:

    • 感谢您提供非常丰富的答案!对于我的目的而言,将 javascript 代码插入 mongo 似乎需要很长时间,但很高兴知道这是可能的。
    猜你喜欢
    • 2020-03-22
    • 2016-06-18
    • 2019-07-19
    • 1970-01-01
    • 2015-02-13
    • 2015-09-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多