How to find MongoDB field name at arbitrary depth

I imported the invalid XML data into the Mongo database. Each document has subdocuments to a depth of about 5-10. I would like to find () documents that have a specific value for a specific field, where the field can be displayed at any depth in subtopies (and can appear several times).

Currently, I take out each document in Python and then look through this dictionary, but it would be nice if I could specify a filter prototype in which the database will only return documents that have a specific field name value somewhere in their content.

Here is a sample document:

{ "foo": 1, "bar": 2, "find-this": "Yes!", "stuff": { "baz": 3, "gobble": [ "wibble", "wobble", { "all-fall-down": 4, "find-this": "please find me" } ], "plugh": { "plove": { "find-this": "Here too!" } } } } 

So, I would like to find documents that have a find-this field and (if possible) to be able to find documents that have a specific find-this field value.

+7
mongodb recursion mongodb-query
source share
2 answers

You are correct in a certain statement of a BSON document, it is not an XML document. Because XML is loaded into a tree structure made up of "nodes", searching by a stern key is fairly straightforward.

A MonoDB document is not easy to process, and in many ways it is a "database", so it is expected that it will have a certain "uniformity" of data locations in order to simplify the "indexing" and search.

However, this can be done. But of course, this means that a recursive process is running on the server, and this means that JavaScript is processed using $where .

As a basic shell example, but a generic function is just a string argument to the $where operator everywhere:

 db.collection.find( function () { var findKey = "find-this", findVal = "please find me"; function inspectObj(doc) { return Object.keys(doc).some(function(key) { if ( typeof(doc[key]) == "object" ) { return inspectObj(doc[key]); } else { return ( key == findKey && doc[key] == findVal ); } }); } return inspectObj(this); } ) 

So, basically, check the keys present in the object to see if they match the desired โ€œfield nameโ€ and contents. If one of these keys is an โ€œobjectโ€, then go to the function and check again.

JavaScript .some() ensures that the match found is returned from the search function, giving the result true and returning the object where this key / value was present at some depth.

Note that $where essentially means moving your entire collection if there is no other valid query filter that can be applied to the "index" in the collection.

So use with caution or donโ€™t work at all and just work with restructuring the data into a more usable form.

But it will give you your match.

+7
source share

Here is one example that I use to recursively search for a key value anywhere in the document structure:

 db.getCollection('myCollection').find({ "$where" : function(){ var searchKey = 'find-this'; var searchValue = 'please find me'; return searchInObj(obj); function searchInObj(obj){ for(var k in obj){ if(typeof obj[k] == 'object' && obj[k] !== null){ if(searchInObj(obj[k])){ return true; } } else { if(k == searchKey && obj[k] == searchValue){ return true; } } } return false; } } }) 
+2
source share

All Articles