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

Fjern dubletter på mongodb

hvis du er parat til blot at kassere alle andre dubletter, så ønsker du grundlæggende at .aggregate() for at indsamle dokumenterne med det samme RegisterNumber værdi og fjern alle andre dokumenter end det første match.

MongoDB 3.0.x mangler nogle af de moderne hjælpere, men det grundlæggende, som .aggregate() returnerer en markør for store procesresultatsæt og tilstedeværelsen af ​​"bulk operations" for skriveydelse eksisterer stadig:

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 mere moderne udgivelser ( 3.2 og nyere ) foretrækkes det at bruge bulkWrite() i stedet. Bemærk, at dette er en 'klientbibliotek'-ting, da de samme "bulk"-metoder vist ovenfor faktisk kaldes "under the hood":

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 trækker alt sammen via $RegisterNumber værdi og samler det matchende dokument _id værdier til en matrix. Du holder optællingen af, hvor mange gange dette sker ved at bruge $sum .

Filtrer derefter alle dokumenter fra, der kun havde et antal på 1 da de tydeligvis ikke er dubletter.

Ved at gå videre til løkken fjerner du den første forekomst af _id i den indsamlede liste for nøglen med .shift() , hvilket kun efterlader andre "duplikater" i arrayet.

Disse sendes til "fjern"-operationen med $in som en "liste" over dokumenter, der skal matches og fjernes.

Processen er generelt den samme, hvis du har brug for noget mere komplekst, såsom at flette detaljer fra de andre duplikerede dokumenter, det er bare, at du måske har brug for mere omhu, hvis du gør noget som at konvertere sagen til den "unikke nøgle" og derfor faktisk fjerne dubletterne først før du skriver ændringer til det dokument, der skal ændres.

I hvert fald vil sammenlægningen fremhæve de dokumenter, der faktisk er "duplikater". Den resterende behandlingslogik er baseret på, hvad du rent faktisk ønsker at gøre med disse oplysninger, når du først har identificeret dem.




  1. Hvordan forespørger jeg refererede objekter i MongoDB?

  2. MongoDB:locale::facet::_S_create_c_locale navn er ikke gyldigt

  3. Konverter JSON-forespørgselsbetingelser til MongoDB/Mongoose-operationer

  4. (node:63208) DeprecationWarning:collection.ensureIndex er forældet. Brug createIndex i stedet