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.
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});
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
}
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
.
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
Znalazłem przydatne informacje na oficjalnym blogu mongo lab: http://blog.mongolab.com/2014/03/finding-duplicate-keys-with-the-mongodb-aggregation-framework/
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