MongoDB
 sql >> Base de données >  >> NoSQL >> MongoDB

Supprimer les doublons sur mongodb

si vous êtes prêt à simplement supprimer tous les autres doublons, vous souhaitez essentiellement .aggregate() afin de collecter les documents avec le même RegisterNumber valeur et supprimez tous les autres documents autres que la première correspondance.

MongoDB 3.0.x manque de certains des assistants modernes, mais les bases qui .aggregate() renvoie un curseur pour traiter de grands ensembles de résultats et la présence de "opérations en bloc" pour les performances d'écriture existe toujours :

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

Dans les versions plus modernes (3.2 et supérieures), il est préférable d'utiliser bulkWrite() Au lieu. Notez qu'il s'agit d'une "bibliothèque cliente", car les mêmes méthodes "en masse" présentées ci-dessus sont en fait appelées "sous le capot":

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

Donc $group rassemble tout via le $RegisterNumber value et collecte le document correspondant _id valeurs dans un tableau. Vous gardez le compte du nombre de fois que cela se produit en utilisant $sum .

Filtrez ensuite tous les documents qui n'avaient qu'un nombre de 1 puisque ce ne sont clairement pas des doublons.

En passant à la boucle, vous supprimez la première occurrence de _id dans la liste collectée pour la clé avec .shift() , ne laissant que d'autres "doublons" dans le tableau.

Ceux-ci sont transmis à l'opération "supprimer" avec $in sous forme de "liste" de documents à faire correspondre et à supprimer.

Le processus est généralement le même si vous avez besoin de quelque chose de plus complexe, comme la fusion des détails des autres documents en double, c'est juste que vous pourriez avoir besoin de plus de soin si vous faites quelque chose comme convertir la casse de la "clé unique" et donc supprimer les doublons en premier avant d'écrire les changements dans le document à modifier.

Dans tous les cas, l'agrégation mettra en évidence les documents qui sont en réalité des "doublons". La logique de traitement restante est basée sur ce que vous voulez réellement faire avec ces informations une fois que vous les avez identifiées.