通过关键字段查找MongoDB集合中的所有重复文档

Moh*_*hit 52 mapreduce duplicates mongodb aggregation-framework

假设我有一些包含一些文档的集合.这样的事情.

{ "_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"}
Run Code Online (Sandbox Code Playgroud)

我想通过"name"字段找到此集合中的所有重复条目.例如,"foo"出现两次,"bar"出现3次.

exp*_*ert 147

接受的答案在大型集合上非常慢,并且不会返回_id重复记录的s.

聚合更快,可以返回_ids:

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 }
]);
Run Code Online (Sandbox Code Playgroud)

在聚合管道的第一阶段,$ group 运算符按name字段聚合文档,并存储在分组记录的uniqueIds每个_id值中.该$和运营商加起来传递给它,在这种情况下,不断的字段的值1-借此计算的分组的记录数量到count现场.

在管道的第二阶段,我们使用$ match 来过滤count至少为2的文档,即重复文件.

然后,我们首先对最常见的重复项进行排序,并将结果限制在前10位.

此查询将输出$limit具有重复名称的记录及其_ids.例如:

{
  "_id" : {
    "name" : "Toothpick"
},
  "uniqueIds" : [
    "xzuzJd2qatfJCSvkN",
    "9bpewBsKbrGBQexv4",
    "fi3Gscg9M64BQdArv",
  ],
  "count" : 3
},
{
  "_id" : {
    "name" : "Broom"
  },
  "uniqueIds" : [
    "3vwny3YEj2qBsmmhA",
    "gJeWGcuX6Wk69oFYD"
  ],
  "count" : 2
}
Run Code Online (Sandbox Code Playgroud)


ggr*_*ner 17

注意:此解决方案最容易理解,但不是最好的解决方案.

您可以使用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});
Run Code Online (Sandbox Code Playgroud)


Pra*_*dra 5

对于通用的Mongo解决方案,请参阅MongoDB cookbook配方以查找重复项group.请注意,聚合更快,更强大,因为它可以返回_id重复记录的s.

对于,接受的答案(使用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);
Run Code Online (Sandbox Code Playgroud)

输出将是这样的:

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

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

        )

    [count] => 3
    [keys] => 2
    [ok] => 1
)
Run Code Online (Sandbox Code Playgroud)

等效的SQL查询将是:SELECT name, COUNT(name) FROM prb GROUP BY name.请注意,我们仍然需要从数组中过滤掉计数为0的元素.再次,请参阅MongoDB cookbook配方,以查找使用group规范解决方案的重复项group.