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”.