mongodb duplicate value
Encuentre todos los documentos duplicados en una colección MongoDB por un campo clave (4)
Encontré información útil en el blog oficial de mongo lab: http://blog.mongolab.com/2014/03/finding-duplicate-keys-with-the-mongodb-aggregation-framework/
Supongamos que tengo una colección con algunos conjuntos de documentos. algo como esto.
{ "_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"}
Quiero encontrar todas las entradas duplicadas en esta colección por el campo "nombre". Por ejemplo, "foo" aparece dos veces y "bar" aparece 3 veces.
La respuesta aceptada es terriblemente lenta en colecciones grandes y no devuelve los _id
de los registros duplicados.
La agregación es mucho más rápida y puede devolver los _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 }
]);
En la primera etapa de la canalización de agregación, el operador de $group agrega documentos por el campo de name
y almacena en uniqueIds
cada valor de _id
de los registros agrupados. El operador $sum suma los valores de los campos pasados a él, en este caso la constante 1
- contando así el número de registros agrupados en el campo de count
.
En la segunda etapa de la canalización, utilizamos $match para filtrar documentos con un count
de al menos 2, es decir, duplicados.
Luego, primero ordenamos los duplicados más frecuentes y limitamos los resultados al top 10.
Esta consulta generará hasta $limit
registros de $limit
con nombres duplicados, junto con sus _id
s. Por ejemplo:
{
"_id" : {
"name" : "Toothpick"
},
"uniqueIds" : [
"xzuzJd2qatfJCSvkN",
"9bpewBsKbrGBQexv4",
"fi3Gscg9M64BQdArv",
],
"count" : 3
},
{
"_id" : {
"name" : "Broom"
},
"uniqueIds" : [
"3vwny3YEj2qBsmmhA",
"gJeWGcuX6Wk69oFYD"
],
"count" : 2
}
Nota: esta solución es la más fácil de entender, pero no la mejor.
Puede usar mapReduce
para averiguar cuántas veces un documento contiene un determinado campo:
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});
Para obtener una solución genérica de Mongo, consulte la receta del libro de cocina de MongoDB para encontrar duplicados con el group
. Tenga en cuenta que la agregación es más rápida y más potente ya que puede devolver los _id
de los registros duplicados.
Para pymongo , la respuesta aceptada (usando mapReduce) no es tan eficiente. En cambio, podemos usar el método de 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);
La salida será esta:
Array
(
[retval] => Array
(
[0] => Array
(
[name] =>
[count] => 1
)
[1] => Array
(
[name] => MongoDB
[count] => 2
)
)
[count] => 3
[keys] => 2
[ok] => 1
)
La consulta SQL equivalente sería: SELECT name, COUNT(name) FROM prb GROUP BY name
. Tenga en cuenta que todavía tenemos que filtrar elementos con un recuento de 0 de la matriz. Una vez más, consulte la receta del libro de cocina de MongoDB para encontrar duplicados usando el group
para la solución canónica utilizando el group
.