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);
Så $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.