Znajdź wszystkie duplikaty dokumentów w kolekcji MongoDB według pola klucza

Przypuśćmy, że mam zbiór dokumentów. coś w tym stylu.

{ "_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"}

Chcę znaleźć wszystkie zduplikowane wpisy w tej kolekcji w polu "Nazwa". Np. " foo "pojawia się dwa razy, a" bar " trzy razy.

Author: ekad, 2012-02-29

4 answers

Uwaga: To rozwiązanie jest najłatwiejsze do zrozumienia, ale nie najlepsze.

Możesz użyć mapReduce aby dowiedzieć się, ile razy dokument zawiera określone pole:

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});
 17
Author: ggreiner,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-15 22:28:40

Akceptowana odpowiedź jest strasznie powolna w przypadku dużych zbiorów i nie zwraca _id S zduplikowanych rekordów.

Agregacja jest znacznie szybsza i może zwracać _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 }
]);

W pierwszym etapie potoku agregacji Grupa $ operator agreguje dokumenty według pola name i przechowuje w uniqueIds każdą wartość _id zgrupowanych rekordów. Operator $ sum sumuje wartości przekazywanych do niego pól, w tym przypadku stała 1 - w ten sposób liczymy liczbę zgrupowanych rekordów w polu count.

W drugim etapie rurociągu używamy $match filtrowanie dokumentów za pomocą count co najmniej 2, tj. duplikatów.

Następnie najpierw sortujemy najczęstsze duplikaty i ograniczamy wyniki do pierwszej 10.

To zapytanie wyświetli do $limit rekordów o zduplikowanych nazwach wraz z ich _id s. na przykład:

{
  "_id" : {
    "name" : "Toothpick"
},
  "uniqueIds" : [
    "xzuzJd2qatfJCSvkN",
    "9bpewBsKbrGBQexv4",
    "fi3Gscg9M64BQdArv",
  ],
  "count" : 3
},
{
  "_id" : {
    "name" : "Broom"
  },
  "uniqueIds" : [
    "3vwny3YEj2qBsmmhA",
    "gJeWGcuX6Wk69oFYD"
  ],
  "count" : 2
}
 138
Author: expert,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-06 20:50:02

Aby znaleźć ogólne rozwiązanie Mongo, Zobacz przepis MongoDB cookbook, aby znaleźć duplikaty za pomocą group. Zauważ, że agregacja jest szybsza i potężniejsza, ponieważ może zwracać _id s zduplikowanych rekordów.

Dla pymongo , przyjęta odpowiedź (używając mapReduce) nie jest aż tak skuteczna. Zamiast tego możemy użyć metody 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);

Wyjście będzie takie:

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

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

        )

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

Równoważne zapytanie SQL będzie: SELECT name, COUNT(name) FROM prb GROUP BY name. Należy pamiętać, że nadal musimy odfiltruj elementy z liczbą 0 z tablicy. Ponownie zapoznaj się z przepisem MongoDB cookbook, aby znaleźć duplikaty za pomocą group dla rozwiązania kanonicznego za pomocą group.

 5
Author: Prasanth Bendra,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-04-24 06:38:43
 2
Author: Krunal Shah,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-10-14 08:38:26