sql >> Database >  >> NoSQL >> MongoDB

Verwijder duplicaten op mongodb

als je bereid bent om alle andere duplicaten gewoon weg te gooien, dan wil je eigenlijk .aggregate() om de documenten op te halen met hetzelfde RegisterNumber waarde en verwijder alle andere documenten behalve de eerste overeenkomst.

MongoDB 3.0.x mist enkele van de moderne helpers, maar de basis die .aggregate() retourneert een cursor voor proces grote resultaatsets en de aanwezigheid van "bulkbewerkingen" voor schrijfprestaties bestaat nog steeds:

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 modernere releases ( 3.2 en hoger ) wordt bij voorkeur gebruikt bulkWrite() in plaats van. Merk op dat dit een 'clientbibliotheek'-ding is, aangezien dezelfde "bulk"-methoden die hierboven worden getoond, eigenlijk "onder de motorkap" worden genoemd:

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

Dus $group haalt alles bij elkaar via het $RegisterNumber waarde en verzamelt het overeenkomende document _id waarden naar een array. U houdt bij hoe vaak dit gebeurt met $sum .

Filter vervolgens alle documenten uit die slechts een telling van 1 . hadden aangezien dit duidelijk geen duplicaten zijn.

Als u naar de lus gaat, verwijdert u de eerste keer dat _id . voorkomt in de verzamelde lijst voor de sleutel met .shift() , waardoor alleen andere "duplicaten" in de array overblijven.

Deze worden doorgegeven aan de bewerking "verwijderen" met $in als een "lijst" met documenten om te matchen en te verwijderen.

Het proces is over het algemeen hetzelfde als je iets ingewikkelders nodig hebt, zoals het samenvoegen van details uit de andere dubbele documenten, het is alleen dat je misschien meer zorg nodig hebt als je zoiets doet als het omzetten van de "unieke sleutel" en daarom de duplicaten eigenlijk eerst verwijdert voordat u wijzigingen in het te wijzigen document schrijft.

In ieder geval zal de aggregatie de documenten markeren die eigenlijk "duplicaten" zijn. De resterende verwerkingslogica is gebaseerd op wat u ook echt met die informatie wilt doen zodra u ze identificeert.




  1. Spring boot starter data rest, @Notnull beperking werkt niet

  2. Controleer het huidige aantal verbindingen met MongoDb

  3. Subdocumentarray retourneren via Meteor / Mongo

  4. Mongodb, $ som met voorwaarde