sql >> Databasteknik >  >> NoSQL >> MongoDB

MongoDB Duplicera dokument även efter att ha lagt till unik nyckel

Grattis, du verkar ha hittat ett fel. Detta händer bara med MongoDB 3.0.0 i mina tester, eller är åtminstone inte närvarande i MongoDB 2.6.6. Bugg nu registrerad på SERVER-17599

OBS :Inte faktiskt ett "problem" men bekräftat "by design". Släppte alternativet för version 3.0.0. Finns dock fortfarande i dokumentationen.

Problemet är att indexet inte skapas och det uppstår fel när du försöker skapa detta på en samling med befintliga dubbletter i fälten "sammansatt nyckel". På ovanstående bör indexskapandet ge detta i skalet:

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

När det inte finns några dubbletter kan du skapa indexet som du för närvarande försöker och det kommer att skapas.

Så för att komma runt detta, ta först bort dubbletterna med en procedur så här:

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

Då infogas inte ytterligare bilagor som innehåller dubbletter av data och rätt fel kommer att registreras.

Den sista anmärkningen här är att "dropDups" inte är/var en särskilt elegant lösning för att ta bort dubbletter av data. Du vill verkligen ha något med mer kontroll som visas ovan.

För den andra delen, istället för att använda .insert() använd .update() metod. Den har ett "upsert"-alternativ

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

Så de "hittade" dokumenten "modifieras" och de dokument som inte hittas "infogas". Se även $setOnInsert för ett sätt att bara skapa viss data när dokumentet faktiskt infogas och inte när det ändras.

För ditt specifika försök, korrekt syntax för .update() är tre argument. "query", "update" och "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 av uppdateringsoperationerna tillåts "åtkomst till samma sökväg" som används i en annan uppdateringsoperation i det "uppdaterings" dokumentavsnittet.



  1. Rails Redis inställning av maxmemory och maxmemory-policy

  2. Hadoop Map/Reduce vs inbyggd Map/Reduce

  3. Ställa in utgångstid för en samling i mongodb med mongoose

  4. MapReduce verkar begränsade till 100?