MongoDB
 sql >> Base de Dados >  >> NoSQL >> MongoDB

Remover duplicatas no mongodb


se você estiver preparado para simplesmente descartar todas as outras duplicatas, basicamente você deseja .aggregate() para coletar os documentos com o mesmo RegisterNumber valor e remova todos os outros documentos que não sejam a primeira correspondência.

O MongoDB 3.0.x não possui alguns dos auxiliares modernos, mas o básico que .aggregate() retorna um cursor para grandes conjuntos de resultados do processo e a presença de "bulk operations" para desempenho de gravação ainda 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();

Em versões mais modernas ( 3.2 e superiores ) é preferível usar bulkWrite() em vez de. Observe que isso é uma coisa de 'biblioteca de cliente', pois os mesmos métodos "em massa" mostrados acima são realmente chamados "sob o 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);

Então $group reúne tudo através do $RegisterNumber value e coleta o documento correspondente _id valores para uma matriz. Você mantém a contagem de quantas vezes isso acontece usando $sum .

Em seguida, filtre quaisquer documentos que tenham apenas uma contagem de 1 uma vez que esses claramente não são duplicados.

Passando para o loop você remove a primeira ocorrência de _id na lista coletada para a chave com .shift() , deixando apenas outras "duplicatas" na matriz.

Eles são passados ​​para a operação "remove" com $in como uma "lista" de documentos para combinar e remover.

O processo geralmente é o mesmo se você precisar de algo mais complexo, como mesclar detalhes de outros documentos duplicados, só que você pode precisar de mais cuidado ao fazer algo como converter o caso da "chave única" e, portanto, remover as duplicatas primeiro antes de escrever as alterações no documento a ser modificado.

De qualquer forma, a agregação destacará os documentos que realmente são "duplicados". A lógica de processamento restante é baseada no que você realmente deseja fazer com essas informações depois de identificá-las.