通过关键字段查找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食谱使用group
find重复的食谱 。 请注意,聚合更快更强大,因为它可以返回重复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/