1

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?

fgalan
  • 11,732
  • 9
  • 46
  • 89
  • Regarding "Any hint on how it [concurrent access using arrays] could be done?" I can ask in a separate question, if community think is better. – fgalan Jul 26 '15 at 20:32
  • What do you think the problem with concurrent acceess is here exactly? explain why you think an array causes problems. – Blakes Seven Jul 26 '15 at 22:06
  • I have elaborate on the problem in a separate question http://stackoverflow.com/questions/31643054/concurrent-update-of-array-elements-which-are-embedded-documents-in-mongodb. Thanks for your help! – fgalan Jul 26 '15 at 23:35

1 Answers1

1

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.

kimb
  • 15
  • 7
Blakes Seven
  • 49,422
  • 14
  • 129
  • 135
  • Thank you for so detailed answer! As you explain, using an array for `attrs` may make the query much easier, but there are reasons for not using an array in my application (I have edited the original question to elaborate on it). – fgalan Jul 26 '15 at 20:33
  • Related with this, I have found at http://stackoverflow.com/questions/9200399/replacing-embedded-document-in-array-in-mongodb that "In my experience, the array of objects pattern is not optimal if the objects have a natural ID" (in this caes the natural ID is the "key" of the attr, e.g. A1, A2, etc.). – fgalan Jul 26 '15 at 23:37