Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 992
Elliot.Pitts Avatar asked Jun 24 '13 11:06

Elliot.Pitts


People also ask

What is graphLookup in MongoDB?

Definition. $graphLookup. Changed in version 5.1. Performs a recursive search on a collection, with options for restricting the search by recursion depth and query filter.

How do I search for keywords in MongoDB?

In MongoDB, we can perform text search using text index and $text operator. Text index: MongoDB proved text indexes that are used to find the specified text from the string content. Text indexes should be either a string or an array of string elements.

Is lookup slow in MongoDB?

It is slow because it is not using an index. For each document in the logs collection, it is doing a full collection scan on the graphs collection.

How can you implement 1 to many relationships in MongoDB?

In MongoDB, one-to-one, one-to-many, and many-to-many relations can be implemented in two ways: Using embedded documents. Using the reference of documents of another collection.


1 Answers

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.

like image 168
WiredPrairie Avatar answered Oct 09 '22 23:10

WiredPrairie