2015-11-23 70 views
2

對於以下知識文檔,我試圖刪除包含ID的節點= 123mongodb的刪除嵌套對象而不對象節點

{ 
     '_id': "1234567890", 
     "image" : { 
      "unknown-node-1" : { 
       "id" : 123 
      }, 
      "unknown-node-2" : { 
       "id" : 124 
      } 
     } 
    } 

結果應該是如下。

{ 
    '_id': "1234567890", 
    "image" : {   
     "unknown-node-2" : { 
      "id" : 124 
     } 
    } 
} 

以下查詢獲得結果。但是我必須提前知道未知節點1。我怎樣才能做到這一點我是形象。*。結果,而節點的預知識,但只有 信息ID = 123

(*表示未知節點)

是否有可能在蒙戈?或者我應該在應用程序代碼中查找這些內容。

db.test.update({'_id': "1234567890"}, {$unset: {'image.unknown-node-1': ""}}) 
+0

如果你不事先知道該子文檔的名稱,你不能和你有正確的文檔結構做現在。如果將所有「unknown-node-N」文檔放入數組中,則可以執行此操作。 –

回答

3

法伊茲,

沒有運營商幫助匹配和項目一個鍵值對不知道的關鍵。您必須編寫後處理代碼才能掃描每個文檔以查找具有該id的節點,然後執行刪除操作。

如果您有更改架構的自由,您將擁有更多的靈活性。與文檔的設計是這樣的:

{ 
     '_id': "1234567890", 
     "image" : [ 
      {"id" : 123, "name":"unknown-node-1"}, 
      {"id" : 124, "name":"unknown-node-2"}, 
      {"id" : 125, "name":"unknown-node-3"} 
     ] 
    } 

你可以從數組中刪除的文件是這樣的:

db.collectionName.update(
    {'_id': "1234567890"}, 
    { $pull: { image: { id: 123} } } 
) 

這將導致:

{ 
    '_id': "1234567890", 
    "image" : [ 
      {"id" : 124, "name":"unknown-node-2"}, 
      {"id" : 125, "name":"unknown-node-3"} 
     ] 
} 
+1

可以自由地改變設計,並在查看Chridam對地圖縮小的答案後繼續使用該選項。 –

+1

是的,當談到Mongodb時,Chridam似乎總是知道如何爲最困難的情況提供解決方案,我從他的許多答案中獲得靈感。我很高興能夠幫忙! – inspired

1

以您目前的模式,你會需要一種機制來獲取在執行更新之前需要組裝查詢的動態密鑰列表,並且可以採用以下方法之一:MapReduce。就拿下面的地圖,減少操作,將填充單獨收集的所有鍵作爲_id值:

mr = db.runCommand({ 
    "mapreduce": "test", 
    "map" : function() { 
     for (var key in this.image) { emit(key, null); } 
    }, 
    "reduce" : function(key, stuff) { return null; }, 
    "out": "test_keys" 
}) 

要獲得所有動態密鑰列表,在結果集合運行不同:

> db[mr.result].distinct("_id") 
[ "unknown-node-1", "unknown-node-2" ] 

現在給出上面的列表,您可以通過創建一個將其屬性設置爲循環的對象來組裝您的查詢。一般來說,如果你知道這個組鍵,您的查詢都會有這樣的結構:

var query = { 
     "image.unknown-node-1.id": 123 
    }, 
    update = { 
     "$unset": { 
      "image.unknown-node-1": "" 
     } 
    }; 
db.test.update(query, update); 

但由於節點是動態的,你將不得不遍歷從精簡操作並且爲每個元素返回的列表,創建查詢和更新參數如上更新集合。這個列表可能很大,所以爲了獲得最大效率,如果你的MongoDB服務器是2.6或更新版本,最好利用使用寫命令Bulk API,以允許執行批量更新操作,這些操作只是抽象服務器可以輕鬆構建批量操作,從而可以在大型集合中獲得性能提升。這些批量操作來主要有兩種形式:

  • 有序批量操作。這些操作按順序執行所有操作,並在第一次寫入錯誤時出錯。
  • 無序批量操作。這些操作並行執行所有操作並聚合所有錯誤。無序批量操作不保證執行順序。

請注意,對於比2.6更早的服務器,API將下載轉換操作。然而,它不可能下變換100%,因此可能會出現一些無法正確報告正確數字的邊緣情況。

在你的情況,你可以實現這樣的大宗原料藥更新操作:

mr = db.runCommand({ 
    "mapreduce": "test", 
    "map" : function() { 
     for (var key in this.image) { emit(key, null); } 
    }, 
    "reduce" : function(key, stuff) { return null; }, 
    "out": "test_keys" 
}) 
// Get the dynamic keys 
var dynamic_keys = db[mr.result].distinct("_id"); 

// Get the collection and bulk api artefacts 
var bulk = db.test.initializeUnorderedBulkOp(), // Initialize the Unordered Batch 
    counter = 0;  

// Execute the each command, triggers for each key 
dynamic_keys.forEach(function(key) {    
    // Create the query and update documents 
    var query = {}, 
     update = { 
      "$unset": {} 
     }; 

    query["image."+ key +".id"] = 123; 
    update["$unset"]["image." + key] = ";" 

    bulk.find(query).update(update);    
    counter++; 

    if (counter % 100 == 0) { 
     bulk.execute() { 
     // re-initialise batch operation   
     bulk = db.test.initializeUnorderedBulkOp(); 
    } 
});    

if (counter % 100 != 0) { bulk.execute(); } 
+1

upvoted作爲解決方案邏輯上會讓我的問題得到解答(沒有試圖實現你的答案)。但你的回答確實激發我改變了mongdb設計。謝謝。 –