Elliot.Pitts
Elliot.Pitts

Reputation: 71

Mongodb recursive search

I need to search through a collection of documents but also any subdocuments and rename a field titled "en" to "en-GB" in every occurrence, I have tried this code but keep getting a JavaScript execution failed: RangeError: Maximum call stack size exceeded error. The problem is searching through the subdocuments using the function without knowing there path.

remap = function (x) {
  if (x.en){
        db.products.update({_id:x._id}, {$rename:{"en":"en-GB"}}, false, true); }
for (var propt in x) {
    if (Object.prototype.toString.call( x[propt] ) === '[object Array]' || 
        Object.prototype.toString.call( x[propt] ) === '[object Object]'){
       remap(x[propt]);
    }
}

}

I have also written something similar that instead adds it to a queue using an array, but need a way of saving the sub-documents path such as "document.subdocument" and then running it through the function again to check for the field.

Upvotes: 6

Views: 1497

Answers (1)

WiredPrairie
WiredPrairie

Reputation: 59793

You might try something like below.

First, just use rename on all documents in the collection:

db.products.update({}, {$rename:{"en":"en-GB"}}, false, true); 

There's no reason to do that in the remap function. Further, the syntax you used means update all documents (not a specific document) by updating en to en-GB.

If you wanted to update just a single specific document, you'd need to specify the document by _id for example:

db.products.update({_id : x._id}, {$rename:{"en":"en-GB"}}, false, true); 

Then, modify your remap function to loop through all properties of each document, and grab the value and check its type:

var remap = function (x) {
    for (var propt in x) {
        var val = x[propt];
        var type = Object.prototype.toString.call( val );
        if (type === '[object Array]' || type === '[object Object]') {
           remap(val);
        }
    }
};

It could be recursively called as shown. However, this won't rename the properties of sub-objects. That's more complex and you'll need to pass in the full document for each, maintain it recursively, and then update all properties of the document at once (using property paths, like "subobject.locale" or resaving the entire document). Arrays may be more difficult to do in place, as you'll need to remove the object in the array, and reinsert it at the same index with the new modifications (or use array index specifiers). If you save the entire document, you could modify them all in place, which would be simpler.

Honestly, I'd do this using your favorite programming language rather than from the shell at this point.

Upvotes: 3

Related Questions