通过关键字段查找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”出现三次。

注意:这个解决scheme是最容易理解的,但不是最好的。

您可以使用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}); 

被接受的答案在大集合上非常缓慢,并且不会返回重复logging的_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 } ]); 

在聚合stream水线的第一阶段, $ group操作符按name字段聚合文档,并在uniqueIds存储分组logging的每个_id值。 $ sum运算符将传递给它的字段的值相加 ,在这种情况下是常量1 ,从而将count字段中分组logging的count

在stream水线的第二阶段,我们使用$ match来过滤至less有2个count的文档,即重复。

然后,我们首先sorting最频繁的重复,并将结果限制在前10位。

此查询将输出最多$limit重复名称的logging以及它们的_id 。 例如:

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

对于一个通用的Mongo解决scheme,请参阅MongoDB食谱使用groupfind重复的食谱 。 请注意,聚合更快更强大,因为它可以返回重复logging的_id

对于pymongo ,接受的答案(使用mapReduce)并不是那么高效。 相反,我们可以使用组方法:

 $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食谱手册,find使用group的规范化解决scheme的重复项 。

我在官方的mongo实验室博客上find了有用的信息: http : //blog.mongolab.com/2014/03/finding-duplicate-keys-with-the-mongodb-aggregation-framework/