MongoDB
 sql >> Baza danych >  >> NoSQL >> MongoDB

MongoDB Duplikaty dokumentów nawet po dodaniu unikalnego klucza

Gratulacje, wygląda na to, że znalazłeś błąd. Dzieje się tak tylko z MongoDB 3.0.0 w moich testach, a przynajmniej nie występuje w MongoDB 2.6.6. Błąd zarejestrowany na SERVER-17599

UWAGA :W rzeczywistości nie jest to „problem”, ale potwierdzony „zgodnie z projektem”. Porzucono opcję dla wersji 3.0.0. Jednak nadal jest wymieniony w dokumentacji.

Problem polega na tym, że indeks nie jest tworzony i występują błędy podczas próby utworzenia tego w kolekcji z istniejącymi duplikatami w polach „klucza złożonego”. W przypadku powyższego, tworzenie indeksu powinno dać w powłoce to:

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

Jeśli nie ma duplikatów, możesz utworzyć indeks, tak jak obecnie próbujesz, i zostanie on utworzony.

Aby obejść ten problem, najpierw usuń duplikaty za pomocą procedury takiej jak ta:

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

Następnie dalsze wstawki zawierające zduplikowane dane nie zostaną wstawione, a odpowiedni błąd zostanie zarejestrowany.

Ostatnia uwaga jest taka, że ​​„dropDups” nie jest/nie był bardzo eleganckim rozwiązaniem do usuwania zduplikowanych danych. Naprawdę chcesz czegoś z większą kontrolą, jak pokazano powyżej.

W drugiej części zamiast używać .insert() użyj .update() metoda. Ma opcję „upsert”

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

Tak więc „znalezione” dokumenty są „zmodyfikowane”, a te, które nie zostały znalezione, są „wstawiane”. Zobacz także $setOnInsert aby uzyskać sposób na tworzenie określonych danych tylko wtedy, gdy dokument jest faktycznie wstawiony, a nie po zmodyfikowaniu.

Dla Twojej konkretnej próby poprawna składnia .update() to trzy argumenty. "zapytanie", "aktualizacja" i "opcje":

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

Żadna z operacji aktualizacji nie ma „dostępu do tej samej ścieżki”, jaka została użyta w innej operacji aktualizacji w tej sekcji dokumentu „aktualizacja”.



  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. mangusta/mongodb zapytanie wielokrotnego sortowania

  2. Usuwanie klucza/wartości z istniejącego wpisu MongoDB

  3. MongoDB $odejmowanie

  4. Czy w zapytaniu MongoDB można używać ścisłych dat JSON $dates?

  5. Różnice MongoDB między NumberLong a prostą Integer?