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

MongoDB Duplicate Documents, selv efter tilføjelse af unik nøgle

Tillykke, du ser ud til at have fundet en fejl. Dette sker kun med MongoDB 3.0.0 i min test, eller er i det mindste ikke til stede i MongoDB 2.6.6. Fejl er nu registreret på SERVER-17599

BEMÆRK :Faktisk ikke et "problem", men bekræftet "by design". Droppede muligheden for version 3.0.0. Dog stadig opført i dokumentationen.

Problemet er, at indekset ikke bliver oprettet, og der opstår fejl, når du forsøger at oprette dette på en samling med eksisterende dubletter på felterne "sammensat nøgle". På ovenstående skulle indeksoprettelsen give dette i skallen:

{
    "createdCollectionAutomatically" : false,
    "numIndexesBefore" : 1,
    "errmsg" : "exception: E11000 duplicate key error dup key: { : 15.0, : 1.0 }",
    "code" : 11000,
    "ok" : 0
}

Når der ikke er nogen dubletter til stede, kan du oprette indekset, som du i øjeblikket prøver, og det vil blive oprettet.

Så for at omgå dette, skal du først fjerne dubletterne med en procedure som denne:

db.events.aggregate([
    { "$group": {
        "_id": { "uid": "$uid", "sid": "$sid" },
        "dups": { "$push": "$_id" },
        "count": { "$sum": 1 }
    }},
    { "$match": { "count": { "$gt": 1 } }}
]).forEach(function(doc) {
    doc.dups.shift();
    db.events.remove({ "_id": {"$in": doc.dups }});
});

db.events.createIndex({"uid":1 , "sid": 1},{unique:true})

Derefter vil yderligere indstik, der indeholder duplikerede data, ikke blive indsat, og den relevante fejl vil blive registreret.

Den sidste bemærkning her er, at "dropDups" er/ikke var en særlig elegant løsning til at fjerne duplikerede data. Du vil virkelig have noget med mere kontrol som vist ovenfor.

For den anden del, i stedet for at bruge .insert() brug .update() metode. Den har en "upsert" mulighed

$collection->update(
    array( "uid" => 1, "sid" => 1 ),
    array( '$set' => $someData ),
    array( 'upsert' => true )
);

Så de "fundne" dokumenter "modificeres", og de dokumenter, der ikke findes, "indsættes". Se også $setOnInsert for en måde kun at oprette visse data, når dokumentet faktisk er indsat og ikke når det ændres.

For dit specifikke forsøg, den korrekte syntaks for .update() er tre argumenter. "query", "update" og "options":

$collection->update(
    array( "uid" => 1, "sid" => 1 ),
    array(
        '$set' => array( "field" => "this" ),
        '$inc' => array( "counter" => 1 ),
        '$setOnInsert' => array( "newField" => "another" )
   ),
   array( "upsert" => true )
);

Ingen af ​​opdateringshandlingerne får "adgang til den samme sti" som brugt i en anden opdateringshandling i den pågældende "opdaterings" dokumentsektion.



  1. projektion fungerer ikke med find-forespørgsel

  2. Bedste praksis for MongoDB Security

  3. Hvordan indstiller/får man pandas.DataFrame til/fra Redis?

  4. Hent BinData UUID fra Mongo som streng