查询具有给定值的内部子字段的文档 [英] Query for documents which have an internal sub-field of a given value

查看:76
本文介绍了查询具有给定值的内部子字段的文档的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在MongoDB的x集合中有这样的文档:

{
    "_id" : ...
    "attrKeys": [ "A1", "A2" ],
    "attrs" : {
        "A1" : {
            "type" : "T1",
            "value" : "13"
        },
        "A2" : {
            "type" : "T2",
            "value" : "14"
        }
    }
}

上面的A1A2元素仅是示例:attrs字段可以容纳任意数量的任何名称的键. attrs中的键名称存储在attrNames字段中.

我想查询具有attr且具有给定值的子字段的文档.例如,查询在attr键映射中具有元素的文档,该文档的子字段type是"T4".像这样:

db.x.find({"attrs.$any.type": "T4"})

(该avobe不是MongoDB合法的查询语言,但我认为这可能有助于理解这一点.)

使用MongoDB可以查询吗?如果MongoDB不支持该查询,是否有任何解决方法?谢谢!

编辑:数据模型的原始版本使用attrs的数组代替键映射.但是,为了允许在同一文档上进行并发修改,这改变了对键映射的支持.

我的意思是,使用一个键映射,两个独立的客户端可以修改attrs元素,因为一个客户端可以执行db.x.update({_id: "y"}, {$set: { "attrs.A1.value": "12" } },而另一个客户端可以执行db.x.update({_id: "y"}, {$set: { "attrs.A2.value": "55" } }而不互相干扰.

在使用数组的情况下,并发访问要困难得多.关于如何完成的任何提示吗?

解决方案

MongoDB始终可以做到这一点,因为始终可以使用 JavaScript评估:

 db.attrs.find(function() {
    var attrs = this.attrs;
    return Object.keys(attrs).some(function(key) {
       return attrs[key].value === "14"
    });
})
 

通过在文档中的可能键中搜索所需值,可以正确返回符合条件的文档.

但这不是关于可能"的问题,而是这真的是一个好主意" 中的一个问题,其基本答案是否".

数据库是善变的野兽,它们喜欢使用索引之类的东西进行优化,以及它们自己的预期运算符集,以使搜索尽可能高效地使用.因此,可以,您可以使用语言解释器来进行有效的蛮力评估,以评估每个文档中的编码条件,也可以重新考虑您的设计模式.

数据库喜欢顺序",所以给它一些东西,因为对您建议的数据进行了简单的组织重组:

 {
    "attrs" : [
        { "key": "A1", "type" : "T1", "value" : "13" },
        { "key": "A2", "type" : "T2", "value" : "14" }
     ]
}
 

这种组织方式使查询变得简单:

 db.attrs.find({ "attrs.value": "14" })
 

当然可以支持和使用数组中子文档的任何这些属性的索引.

MongoDB毕竟是一个数据库",与所有数据库一样,它最关心其属性的值",而不是使用其键"的名称进行搜索.因此,代表有意义的数据"的事物不应成为键"名称的一部分,而应作为标识符"作为键"的值",如上所示.

对要查询的数据使用一致的路径是在MongoDB内部处理数据的最佳方法.使用键名不断变化的结构,除了运行代码外,其他任何东西都无法遍历该结构,与使用诸如索引之类的本机操作和功能相比,这种操作要慢得多,并且性能会更差. >

I have documents like this one at collection x at MongoDB:

{
    "_id" : ...
    "attrKeys": [ "A1", "A2" ],
    "attrs" : {
        "A1" : {
            "type" : "T1",
            "value" : "13"
        },
        "A2" : {
            "type" : "T2",
            "value" : "14"
        }
    }
}

The A1 and A2 elements above are just examples: the attrs field may hold any number of keys of any name. The key names in attrs are stored in the attrNames field.

I would like to query for documents which have an attr with a sub-field of a given value. For example, a query for documents that have an element in the attr key-map which sub-field type is "T4". Something like this:

db.x.find({"attrs.$any.type": "T4"})

(The avobe is not legal MongoDB query language, but I think it could help to get the idea).

Is that query possible with MongoDB? Is there any workaround in the case MongoDB doesn't support that query? Thanks!

EDIT: original versions of the data model use an array for attrs instead of a key-map. However, that changed in favour of a key-map in order to allow concurrent modifications on the same document.

I mean, using a key-map two independent clients can modify attrs elements, as one client may do db.x.update({_id: "y"}, {$set: { "attrs.A1.value": "12" } } and another client do db.x.update({_id: "y"}, {$set: { "attrs.A2.value": "55" } } without interferring one each other.

In the case of using an array concurrent access is much more harder. Any hint on how it could be done?

解决方案

This has always been possible with MongoDB because there has always been the ability to contruct query conditions using JavaScript evaluation:

db.attrs.find(function() {
    var attrs = this.attrs;
    return Object.keys(attrs).some(function(key) {
       return attrs[key].value === "14"
    });
})

Where that will correctly return the documents that match the condition here by searching the possible keys in the document for the required value.

But it's not really a question on "possible", but more one of "is this really a good idea", for which the basic answer is "No".

Databases are fickle beasts that do like to optimize with things like indexes and such, as well as their own expected operator set to make searching as efficient as possible to use. So yes, you can go through a language interpreter that effectively brute force evaluates a coded condition across each document, or you can reconsider your design pattern.

Databases love "order", so give it some, as there is a simple organized re-structure to the data you propose:

{
    "attrs" : [
        { "key": "A1", "type" : "T1", "value" : "13" },
        { "key": "A2", "type" : "T2", "value" : "14" }
     ]
}

Organized that way the query becomes as simple as:

db.attrs.find({ "attrs.value": "14" })

And can of course support and use an index on any of those properties of the subdocument in the array.

MongoDB is afterall a "database", and like all databases it is most concerned with the "values" of it's properties rather that searching using the names of it's "keys". So things that represent meaningful "data" should not be part of the name of a "key", but rather they should be the "value" of a "key" as an "idendtifier", as demonstrate above.

Have a consistent path to the data you wish to query on is the optimal way to work with data inside MongoDB. Using a structure where key names are contantly changing, cannot be traversed by anything other than running code, and that is so much slower and worse for performance than using the native operations and facilites such as indexes.

这篇关于查询具有给定值的内部子字段的文档的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆