2013-06-24 200 views
5

我需要搜索文檔集合,但也需要搜索任何子文檔,並在每次出現時將標題爲「en」的字段重命名爲「en-GB」,我試過這段代碼,但一直未能執行JavaScript: RangeError:最大調用堆棧大小超出錯誤。問題是在不知道路徑的情況下使用函數搜索子文檔。Mongodb遞歸搜索

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」,然後運行的一種方式它通過函數再次檢查該字段。

+0

對象中是否有循環引用? X指向Y,Y指向Z,Z指向X?這會導致堆棧溢出。 – Brandon

+0

您應該使用'x [propt]'而不是'propt'的值,因爲這只是'x'屬性的名稱。 – WiredPrairie

回答

3

你可能會嘗試下面的東西。

首先,只需要使用重命名集合中的所有文件:

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

沒有理由這樣做,在重映射功能。此外,您使用的語法意味着通過將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。

+0

是否可以將子文檔路徑(如「product.description」)保存爲可以通過該函數運行的字符串。我需要一種掃描所有文檔和所有子文檔的方法,然後需要重命名它。 –

+0

根據編程語言,是的。如果它只是一個JavaScript對象,你只需設置必要的屬性。 – WiredPrairie