sql >> Base de Datos >  >> NoSQL >> MongoDB

Eliminar duplicados en mongodb

si está preparado para simplemente descartar todos los demás duplicados, entonces básicamente desea .aggregate() para recoger los documentos con el mismo RegisterNumber valor y elimine todos los demás documentos que no sean la primera coincidencia.

MongoDB 3.0.x carece de algunos de los ayudantes modernos, pero los elementos básicos .aggregate() devuelve un cursor para procesar grandes conjuntos de resultados y la presencia de "operaciones masivas" para el rendimiento de escritura todavía existe:

var bulk = db.collection.initializeOrderedBulkOp();
var count = 0;

db.collection.aggregate([
  // Group on unique value storing _id values to array and count 
  { "$group": {
    "_id": "$RegisterNumber",
    "ids": { "$push": "$_id" },
    "count": { "$sum": 1 }      
  }},
  // Only return things that matched more than once. i.e a duplicate
  { "$match": { "count": { "$gt": 1 } } }
]).forEach(function(doc) {
  var keep = doc.ids.shift();     // takes the first _id from the array

  bulk.find({ "_id": { "$in": doc.ids }}).remove(); // remove all remaining _id matches
  count++;

  if ( count % 500 == 0 ) {  // only actually write per 500 operations
      bulk.execute();
      bulk = db.collection.initializeOrderedBulkOp();  // re-init after execute
  }
});

// Clear any queued operations
if ( count % 500 != 0 )
    bulk.execute();

En versiones más modernas (3.2 y superiores), se prefiere usar bulkWrite() en cambio. Tenga en cuenta que se trata de una 'biblioteca de cliente', ya que los mismos métodos "en masa" que se muestran arriba en realidad se denominan "bajo el capó":

var ops = [];

db.collection.aggregate([
  { "$group": {
    "_id": "$RegisterNumber",
    "ids": { "$push": "$id" },
    "count": { "$sum": 1 }      
  }},
  { "$match": { "count": { "$gt": 1 } } }
]).forEach( doc => {

  var keep = doc.ids.shift();

  ops = [
    ...ops,
    {
      "deleteMany": { "filter": { "_id": { "$in": doc.ids } } }
    }
  ];

  if (ops.length >= 500) {
    db.collection.bulkWrite(ops);
    ops = [];
  }
});

if (ops.length > 0)
  db.collection.bulkWrite(ops);

Entonces $group reúne todo a través de $RegisterNumber value y recopila el documento coincidente _id valores a una matriz. Mantiene la cuenta de cuántas veces sucede esto usando $sum .

Luego filtre cualquier documento que solo tenga un recuento de 1 ya que claramente no son duplicados.

Al pasar al bucle, elimina la primera aparición de _id en la lista recopilada para la clave con .shift() , dejando solo otros "duplicados" en la matriz.

Estos se pasan a la operación "eliminar" con $in como una "lista" de documentos para hacer coincidir y eliminar.

El proceso es generalmente el mismo si necesita algo más complejo, como fusionar detalles de los otros documentos duplicados, solo que es posible que necesite más cuidado si hace algo como convertir el caso de la "clave única" y, por lo tanto, eliminar primero los duplicados. antes de escribir cambios en el documento a modificar.

En cualquier caso, la agregación resaltará los documentos que en realidad son "duplicados". La lógica de procesamiento restante se basa en lo que realmente quieras hacer con esa información una vez que la identifiques.