2016-08-01 73 views
0

我目前正在使用MongoDB在線商店,但我不小心重複了「批發商」集合中列出的所有品牌。我一直在尋找一個查詢來刪除或修剪這些重複的條目,但到目前爲止似乎沒有任何工作。MongoDB:刪除陣列列表中的重複條目

db.wholesalers.find().pretty() 

{ 
     "_id" : ObjectId("..."), 
     "brands" : [ 
       "Seiko", 
       "Breil", 
       "Lorus", 
       "Seiko", 
       "Breil", 
       "Lorus", 
     ], 
     "name" : "Seiko Nederlands B.V.", 
     "address" : "Daniel Pichotstraat", 
     "housenr" : "17-31", 
     "postalcode" : "3115JB", 
     "city" : "Schiedam", 
     "phone" : "+31 (0)10 - 400 98 66" 
     "email" : "[email protected]" 
     "web" : "http://www.seiko.nl/Default" 
     "kind" : "Horloges", 
     "country" : "", 
     "brandsNetherlands" : [ ] 
    } 

這是我數據庫中單個文檔的一個例子。正如您所看到的,「品牌」數組中列出的品牌都已被複制,我需要一種方法來擺脫它們。做這個的最好方式是什麼?

+0

你想要做的蒙戈的殼呢? – Mahdi

+0

最簡單的方法是編寫腳本,它將更新所有記錄。並且將來你應該使用operator $ set來防止重複。 – Sabik

回答

0

對於相對較小的數據,則可以通過使用其中您通過在$project階段使用$setUnion操作者創建具有不同品牌值的新陣列的聚合框架實現上述。如果數組包含重複條目,則$setUnion將忽略重複的條目以及元素的順序。

一旦你獲得了新的不同品牌的領域,你會即它檢查給定的陣列是否使用相同的概念與$setUnion運營商獨特的元素需要整個集合中用於過濾文檔的附加字段。從彙總的文件 使用效果陣列通過使用其forEach()方法迭代結果光標和更新每個文件作如下更新您的收藏:

db.wholesalers.aggregate([ 
    { 
     "$project": { 
      "distinctBrands": { "$setUnion": [ "$brands", [] ] }, 
      "hasUniqueBrands": { 
       "$eq": [ 
        { "$size": "$brands" }, 
        { "$size": { "$setUnion": [ "$brands", [] ] } } 
       ] 
      } 
     } 
    }, 
    { "$match": { "hasUniqueBrands": false } } 
]).forEach(function(doc) { 
    db.wholesalers.update(
     { "_id": doc._id }, 
     { "$set": { "brands": doc.distinctBrands } } 
    ) 
}) 

雖然這是最適合於小集合,性能大型集合大大減少了,因爲循環遍歷大型數據集並將每個更新操作發送給服務器會導致計算懲罰。

Bulk()由於寫入操作只發送給服務器一次,因此API可以幫助解決問題並大大提高性能。由於該方法不會向服務器發送每個寫入請求(如同循環中的當前更新語句那樣),但每1000次請求只發送一次,因此使得更新效率更高,速度更快。


使用上述與forEach()循環創建批次相同的概念,我們可以在批量更新集合如下。

在該示範MongoDB中版本>= 2.6 and < 3.2可用Bulk() API使用initializeUnorderedBulkOp()方法在平行於非確定性順序來執行,以及,在批寫入操作:

var bulk = db.wholesalers.initializeUnorderedBulkOp(), 
    counter = 0; // counter to keep track of the batch update size 

    db.wholesalers.aggregate([ 
     { 
      "$project": { 
       "distinctBrands": { "$setUnion": [ "$brands", [] ] }, 
       "hasUniqueBrands": { 
        "$eq": [ 
         { "$size": "$brands" }, 
         { "$size": { "$setUnion": [ "$brands", [] ] } } 
        ] 
       } 
      } 
     }, 
     { "$match": { "hasUniqueBrands": false } } 
    ]).forEach(function(doc) { 
     bulk.find({ "_id": doc._id }).updateOne({ 
      "$set": { "brands": doc.distinctBrands } 
     }); 

     counter++; // increment counter 
     if (counter % 1000 == 0) { 
      bulk.execute(); // Execute per 1000 operations 
      // and re-initialize every 1000 update statements 
      bulk = db.wholesalers.initializeUnorderedBulkOp(); 
     } 
    }); 

下一個示例適用於新的MongoDB版本3.2,該版本從此棄用了Bulk() API,並使用bulkWrite()提供了一套更新的apis。

它使用與上述相同的光標,但使用相同的forEach()遊標方法創建帶批量操作的陣列,以將每個批量寫入文檔推送到陣列。因爲寫命令可以接受不超過1000點的操作,還有的需要組操作有最多1000的操作和重新intialise數組時,迴路達到1000迭代:

var bulkUpdateOps = [];  
db.wholesalers.aggregate([ 
     { 
      "$project": { 
       "distinctBrands": { "$setUnion": [ "$brands", [] ] }, 
       "hasUniqueBrands": { 
        "$eq": [ 
         { "$size": "$brands" }, 
         { "$size": { "$setUnion": [ "$brands", [] ] } } 
        ] 
       } 
      } 
     }, 
     { "$match": { "hasUniqueBrands": false } } 
]).forEach(function(doc){ 
    bulkUpdateOps.push({ 
     "updateOne": { 
      "filter": { "_id": doc._id }, 
      "update": { "$set": { "brands": doc.distinctBrands } } 
     } 
    }); 

    if (bulkUpdateOps.length === 1000) { 
     db.wholesalers.bulkWrite(bulkUpdateOps); 
     bulkUpdateOps = []; 
    } 
});   

if (bulkUpdateOps.length > 0) { db.wholesalers.bulkWrite(bulkUpdateOps); } 
0

您還可以通過應用刪除重複javascript函數給每個文件(見How to get unique array items):

function unique(arr) { 
    var hash = {}, result = []; 
    for (var i = 0, l = arr.length; i < l; ++i) { 
     if (!hash.hasOwnProperty(arr[i])) { 
      hash[ arr[i] ] = true; 
      result.push(arr[i]); 
     } 
    } 
    return result; 
} 

db.wholesalers.find({}).forEach(function(doc){ 
    db.wholesalers.update({"_id" : doc._id}, {$set: {"brands": unique(doc.brands)} }); 
}) 

當然你也可以檢查獨特的品牌陣列具有比原來的品牌列表項少更新文件等之前,但因此它的快速修復數據庫的問題,我不會打擾與性能調整。

0

只需運行該腳本(不前^ _ ^忘記備份)

db.wholesalers.find().forEach(saler => { 
    db.wholesalers.update(
    {_id: saler._id}, 
    {$set: { brands: [...new Set(saler.brands)] }}) 
});