2014-09-01 40 views
1

我有這樣的文件:GROUP BY和刪除文檔基於字段數組大小

{ 
    "_id" : ObjectId("53bcedc39c837bba3e1bf1c2"), 
    id : "abc1", 
    someArray: [ 1 , 10 , 11] 
} 

{ 
    "_id" : ObjectId("53bcedc39c837bba3e1bf1c4"), 
    id : "abc1", 
    someArray: [ 1 , 10] 
} 
... other similar documents with different Ids 

我想遍歷整個收集和刪除文檔,其中someArray是最小的,由id分組。所以在這個例子中,我分組abc1(我得到2個文檔),然後第二個文檔將被刪除,因爲它在someArray中的計數最少。

沒有$count累加器,所以我不明白我可以如何使用$group

此外,將會有1000個這樣的重複的Ids,所以如果有這樣的事情作爲批量檢查/刪除,這將是一件好事(可能是一個愚蠢的問題,對不起,Mongo對我來說都是新的! )

回答

4

刪除「重複」是一個過程,並沒有簡單的方法來「識別」重複和「刪除」他們作爲一個單一的陳述。這裏的另一個特殊之處是查詢表單不能「典型地」確定數組的大小,並且當然不能在文檔中不存在的情況下進行排序。

所有病例基本上回落到

  1. 標識是「重複」的文件列表,然後最好指法要刪除特定文件,或者更重要的是該文件你「唐't'想從可能的重複項中刪除。

  2. 處理該列表以實際執行刪除。

考慮到這一點,你希望擁有的2.6或更高版本的現代化的MongoDB在那裏你可以得到從aggregate方法的光標。你也想在這些版本中最佳速度可用Bulk Operations API

var bulk = db.collection.initializeOrderedBulkOp(); 
var counter = 0; 

db.collection.aggregate([ 
    { "$project": { 
     "id": 1, 
     "size": { "$size": "$someArray" } 
    }}, 
    { "$sort": { "id": 1, "size": -1 } }, 
    { "$group": { 
     "_id": "$id", 
     "docId": { "$first": "$_id" } 
    }} 
]).forEach(function(doc) { 
    bulk.find({ "id": doc._id, "_id": { "$ne": doc.docId }).remove(); 
    counter++; 

    // Send to server once every 1000 statements only 
    if (counter % 1000 == 0) { 
     bulk.execute(); 
     bulk = db.collection.initializeOrderedBulkOp(); // need to reset 
    } 
}); 

// Clean up results that did not round to 1000 
if (counter % 1000 != 0) 
    bulk.execute(); 

你仍然可以做同樣的事情與舊版本的MongoDB,但是從.aggregate()其結果必然是在16MB這是BSON限制。這仍然應該是很多,但使用舊版本,您也可以使用mapReduce輸出到集合。

但是對於一般聚合響應,您會得到一組結果,並且您也沒有其他便捷方法來查找數組的大小。所以多做點工作:

var result = db.collection.aggregate([ 
    { "$unwind": "$someArray" }, 
    { "$group": { 
     "_id": "$id", 
     "id": { "$first": "$id" }, 
     "size": { "$sum": 1 } 
    }}, 
    { "$sort": { "id": 1, "size": -1 } }, 
    { "$group": { 
     "_id": "$id", 
     "docId": { "$first": "$_id" } 
    }} 
]); 

result.result.forEach(function(doc) { 
    db.collection.remove({ "id": doc._id, "_id": { "$ne": doc.docId } }); 
}); 

因此,沒有遊標較大的結果,沒有批量操作使每一個「刪除」需要單獨發送到服務器。

所以在MongoDB中沒有「子查詢」,或者即使有超過「兩個副本」的方式來選出您不希望從其他副本中刪除的文檔。但這是通用的方式。就像一個說明,如果數組的「大小」對於諸如「排序」等目的而言是重要的,那麼最好的方法就是將「大小」作爲文檔的另一個屬性,以便它使得這些操作更容易,無需像這裏所做的那樣「計算」。