MongoDB 递归搜索

6

我需要搜索一组文档,同时还要搜索所有子文档,并将标题为“en”的字段重命名为每个出现的“en-GB”。我尝试了这段代码,但不断出现JavaScript执行失败:RangeError:最大调用堆栈大小超过错误。问题是使用函数搜索子文档,而不知道它们的路径。

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]);
    }
}

我还写了类似的东西,但是使用了数组将其添加到队列中,但需要一种保存子文档路径(例如“document.subdocument”)并再次通过函数运行以检查该字段的方法。


对象中可能存在循环引用吗?X指向Y,Y指向Z,Z又指向X?这将导致堆栈溢出。 - Brandon
你应该使用 x[propt] 而不是 propt 的值,因为 propt 只是 x 属性的名称。 - WiredPrairie
1个回答

3
您可以尝试以下方法。
首先,只需对集合中的所有文档使用重命名即可:
db.products.update({}, {$rename:{"en":"en-GB"}}, false, true); 

在remap函数中没有必要这样做。此外,您使用的语法意味着通过将“en”更新为“en-GB”更新所有文档(而不是特定的文档)。
如果您想要更新单个特定文档,则需要按照例如_id指定文档:
db.products.update({_id : x._id}, {$rename:{"en":"en-GB"}}, false, true); 

然后,修改您的重新映射函数以循环遍历每个文档的所有属性,获取其值并检查其类型:

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);
        }
    }
};

这可以递归调用,如所示。然而,这不会重命名子对象的属性。那更加复杂,您需要为每个子对象传入完整文档,递归地维护它,然后一次性更新文档的所有属性(使用属性路径,例如"subobject.locale"或重新保存整个文档)。在原地执行数组可能更加困难,因为您需要从数组中删除对象,并在相同的索引处重新插入具有新修改的对象(或使用数组索引说明符)。如果保存整个文档,则可以直接修改它们,这将更简单。
老实说,我会使用您喜欢的编程语言来完成这个任务,而不是从shell中进行操作。

是否可以将子文档路径(例如“product.description”)保存到字符串中,然后通过函数运行?我需要一种扫描所有文档和子文档以查找相同字段的方法,然后需要重命名它。 - Elliot.Pitts
根据编程语言而定,如果只是JavaScript对象,您只需设置必要的属性即可。 - WiredPrairie

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接