2012-02-29 82 views
46

假設我有一組包含一些文檔的集合。像這樣的東西。通過關鍵字段查找MongoDB集合中的所有重複文檔

{ "_id" : ObjectId("4f127fa55e7242718200002d"), "id":1, "name" : "foo"} 
{ "_id" : ObjectId("4f127fa55e7242718200002d"), "id":2, "name" : "bar"} 
{ "_id" : ObjectId("4f127fa55e7242718200002d"), "id":3, "name" : "baz"} 
{ "_id" : ObjectId("4f127fa55e7242718200002d"), "id":4, "name" : "foo"} 
{ "_id" : ObjectId("4f127fa55e7242718200002d"), "id":5, "name" : "bar"} 
{ "_id" : ObjectId("4f127fa55e7242718200002d"), "id":6, "name" : "bar"} 

我想通過「名稱」字段查找此集合中的所有重複條目。例如。 「foo」出現兩次,「bar」出現三次。

+0

,拆卸,您可以使用重複[該解決方案(HTTP://計算器。com/a/33364353/1045444) – 2015-10-27 09:48:43

回答

16

注意:這個解決方案是最容易理解的,但不是最好的。

您可以使用mapReduce找出一個文件有多少次含有一定領域:

var map = function(){ 
    if(this.name) { 
     emit(this.name, 1); 
    } 
} 

var reduce = function(key, values){ 
    return Array.sum(values); 
} 

var res = db.collection.mapReduce(map, reduce, {out:{ inline : 1}}); 
db[res.result].find({value: {$gt: 1}}).sort({value: -1}); 
5

對於通用蒙戈的解決方案,請參閱MongoDB cookbook recipe for finding duplicates using group。請注意,聚合更快更強大,因爲它可以返回重複記錄的_id

對於,接受的答案(使用mapReduce)效率不高。相反,我們可以使用group方法:

$connection = 'mongodb://localhost:27017'; 
$con  = new Mongo($connection); // mongo db connection 

$db   = $con->test; // database 
$collection = $db->prb; // table 

$keys  = array("name" => 1); Select name field, group by it 

// set intial values 
$initial = array("count" => 0); 

// JavaScript function to perform 
$reduce  = "function (obj, prev) { prev.count++; }"; 

$g   = $collection->group($keys, $initial, $reduce); 

echo "<pre>"; 
print_r($g); 

輸出將是這樣的:

Array 
(
    [retval] => Array 
     (
      [0] => Array 
       (
        [name] => 
        [count] => 1 
       ) 

      [1] => Array 
       (
        [name] => MongoDB 
        [count] => 2 
       ) 

     ) 

    [count] => 3 
    [keys] => 2 
    [ok] => 1 
) 

等效SQL查詢是:SELECT name, COUNT(name) FROM prb GROUP BY name。請注意,我們仍然需要從數組中過濾掉計數爲0的元素。同樣,請參閱MongoDB cookbook recipe for finding duplicates using group獲取標準解決方案,使用group

+0

MongoDB Cookbook的鏈接已過時並返回404。 – udachny 2018-03-05 16:43:40

131

對於大集合,接受的答案非常緩慢,並且不會返回重複記錄的_id

聚合更快,可以返回_id S:

db.collection.aggregate([ 
    { $group: { 
    _id: { name: "$name" }, // replace `name` here twice 
    uniqueIds: { $addToSet: "$_id" }, 
    count: { $sum: 1 } 
    } }, 
    { $match: { 
    count: { $gte: 2 } 
    } }, 
    { $sort : { count : -1} }, 
    { $limit : 10 } 
]); 

在聚合管道的第一階段,$group 經營者聚集在uniqueIds的每個_id值由name領域的文件和存儲分組記錄。 $sum運算符將傳遞給它的字段的值相加,在此情況下爲常數1 - 從而將分組記錄的數量計入count字段中。

在流水線的第二階段,我們使用$match 來過濾至少爲2的count的文檔,即重複。

然後,我們最常見的重複第一排序,並將結果限制爲前10

此查詢將輸出高達$limit記錄重名,與他們_id小號一起。例如:

{ 
    "_id" : { 
    "name" : "Toothpick" 
}, 
    "uniqueIds" : [ 
    "xzuzJd2qatfJCSvkN", 
    "9bpewBsKbrGBQexv4", 
    "fi3Gscg9M64BQdArv", 
    ], 
    "count" : 3 
}, 
{ 
    "_id" : { 
    "name" : "Broom" 
    }, 
    "uniqueIds" : [ 
    "3vwny3YEj2qBsmmhA", 
    "gJeWGcuX6Wk69oFYD" 
    ], 
    "count" : 2 
} 
+0

要刪除重複項,可以使用[此解決方案](http://stackoverflow.com/a/33364353/1045444) – 2015-10-27 09:48:01

+0

現在怎麼可以我使用C#調用它? – blueprintChris 2017-05-02 09:05:06

+0

此解決方案是否使用密鑰上的現有索引?我關心的是針對非常大的集合,這些集合文檔可能不適合內存。 – Iravanchi 2017-06-04 04:23:56

相關問題