sql >> Databasteknik >  >> NoSQL >> MongoDB

Ta bort dubbletter på mongodb

om du är beredd att helt enkelt kassera alla andra dubbletter vill du i princip .aggregate() för att samla in dokumenten med samma RegisterNumber värde och ta bort alla andra dokument förutom den första matchningen.

MongoDB 3.0.x saknar några av de moderna hjälparna men grunderna som .aggregate() returnerar en markör för process stora resultatuppsättningar och förekomsten av "bulk operationer" för skrivprestanda finns fortfarande:

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

I mer moderna utgåvor ( 3.2 och högre ) är det att föredra att använda bulkWrite() istället. Observera att detta är en "klientbibliotek" sak, eftersom samma "bulk" metoder som visas ovan faktiskt kallas "under huven":

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

$group drar ihop allt via $RegisterNumber värde och samlar in det matchande dokumentet _id värden till en array. Du räknar hur många gånger detta händer med $sum .

Filtrera sedan bort alla dokument som bara hade ett antal 1 eftersom de uppenbarligen inte är dubbletter.

När du går till slingan tar du bort den första förekomsten av _id i den insamlade listan för nyckeln med .shift() , lämnar bara andra "dubbletter" i arrayen.

Dessa skickas till "remove"-operationen med $in som en "lista" över dokument att matcha och ta bort.

Processen är i allmänhet densamma om du behöver något mer komplext som att slå samman detaljer från de andra dubblettdokumenten, det är bara det att du kan behöva mer försiktighet om du gör något som att konvertera fallet med den "unika nyckeln" och därför faktiskt ta bort dubbletterna först innan du skriver ändringar i dokumentet som ska modifieras.

I vilket fall som helst kommer aggregeringen att framhäva de dokument som faktiskt är "dubbletter". Den återstående bearbetningslogiken baseras på vad du faktiskt vill göra med den informationen när du väl har identifierat dem.




  1. mongodb count vs hitta med count

  2. hur kan jag skriva om min mongoose-fråga efter att ha delat upp data från en modell i två?

  3. Hur man får avstånd - MongoDB Template Near-funktion

  4. Hur utesluter man dokument från sökresultat med fält som inte finns i frågan?