MongoDB
 sql >> Database >  >> NoSQL >> MongoDB

Rimuovi duplicati su mongodb

se sei pronto a scartare semplicemente tutti gli altri duplicati, fondamentalmente vuoi .aggregate() per ritirare i documenti con lo stesso RegisterNumber valorizza e rimuovi tutti gli altri documenti diversi dalla prima corrispondenza.

MongoDB 3.0.x manca di alcuni degli helper moderni ma delle basi che .aggregate() restituisce un cursore per elaborare set di risultati di grandi dimensioni e la presenza di "operazioni in blocco" per le prestazioni di scrittura esiste ancora:

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();

Nelle versioni più moderne ( 3.2 e successive ) è preferibile utilizzare bulkWrite() invece. Nota che questa è una cosa da "libreria client", poiché gli stessi metodi "in blocco" mostrati sopra sono in realtà chiamati "sotto il cofano":

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);

Quindi $group raccoglie tutto tramite il $RegisterNumber value e raccoglie il documento corrispondente _id valori in una matrice. Mantieni il conteggio di quante volte ciò accade utilizzando $sum .

Quindi filtra tutti i documenti che avevano solo un conteggio di 1 poiché quelli chiaramente non sono duplicati.

Passando al loop rimuovi la prima occorrenza di _id nell'elenco raccolto per la chiave con .shift() , lasciando solo altri "duplicati" nell'array.

Questi vengono passati all'operazione "remove" con $in come "elenco" di documenti da abbinare e rimuovere.

Il processo è generalmente lo stesso se hai bisogno di qualcosa di più complesso come unire i dettagli dagli altri documenti duplicati, è solo che potresti aver bisogno di più cure se fai qualcosa come convertire il caso della "chiave univoca" e quindi rimuovere prima i duplicati prima di scrivere le modifiche al documento da modificare.

In ogni caso, l'aggregazione evidenzierà i documenti che in realtà sono "duplicati". La restante logica di elaborazione si basa su qualsiasi cosa tu voglia effettivamente fare con quelle informazioni una volta che le hai identificate.