MongoDB
 sql >> Datenbank >  >> NoSQL >> MongoDB

Entfernen Sie Duplikate auf mongodb

Wenn Sie bereit sind, alle anderen Duplikate einfach zu verwerfen, dann möchten Sie im Grunde .aggregate() um die Dokumente mit derselben RegisterNummer zu sammeln Wert und entfernen Sie alle anderen Dokumente außer dem ersten Treffer.

MongoDB 3.0.x fehlen einige der modernen Helfer, aber die Grundlagen, die .aggregate() gibt einen Cursor für die Verarbeitung großer Ergebnismengen und das Vorhandensein von "Massenoperationen" zurück für Schreibleistung existiert noch:

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

In moderneren Versionen (3.2 und höher) wird die Verwendung von bevorzugt bulkWrite() stattdessen. Beachten Sie, dass dies eine „Client-Bibliothek“-Sache ist, da dieselben oben gezeigten „Bulk“-Methoden eigentlich „unter der Haube“ genannt werden:

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

Also $group zieht alles über die $RegisterNumber zusammen Wert und sammelt das passende Dokument _id Werte in ein Array. Sie zählen, wie oft dies geschieht, indem Sie $sum verwenden .

Filtern Sie dann alle Dokumente heraus, die nur eine Anzahl von 1 hatten da dies eindeutig keine Duplikate sind.

Beim Übergang zur Schleife entfernen Sie das erste Vorkommen von _id in der gesammelten Liste für den Schlüssel mit .shift() , wobei nur andere "Duplikate" im Array verbleiben.

Diese werden mit $in als "Liste" der abzugleichenden und zu entfernenden Dokumente.

Der Vorgang ist im Allgemeinen derselbe, wenn Sie etwas Komplexeres benötigen, z. B. das Zusammenführen von Details aus den anderen doppelten Dokumenten. Es ist nur so, dass Sie möglicherweise mehr Sorgfalt benötigen, wenn Sie beispielsweise die Groß- und Kleinschreibung des „eindeutigen Schlüssels“ konvertieren und daher zuerst die Duplikate tatsächlich entfernen bevor Änderungen in das zu ändernde Dokument geschrieben werden.

In jedem Fall wird die Aggregation die Dokumente hervorheben, die tatsächlich "Duplikate" sind. Die verbleibende Verarbeitungslogik basiert darauf, was Sie tatsächlich mit diesen Informationen tun möchten, sobald Sie sie identifiziert haben.