Ответ 1
Поздравляем, вы обнаружили ошибку. Это происходит только с MongoDB 3.0.0 в моем тестировании или, по крайней мере, нет в MongoDB 2.6.6. Ошибка теперь записана на SERVER-17599
Примечание: На самом деле "проблема", но подтверждена "по дизайну". Выбросил вариант для версии 3.0.0. Тем не менее, он включен в .
Проблема заключается в том, что индекс не создается и ошибки при попытке создать его в коллекции с существующими дубликатами в полях "составной ключ". В этом случае создание индекса должно дать это в оболочке:
{
"createdCollectionAutomatically" : false,
"numIndexesBefore" : 1,
"errmsg" : "exception: E11000 duplicate key error dup key: { : 15.0, : 1.0 }",
"code" : 11000,
"ok" : 0
}
Если нет дубликатов, вы можете создать индекс, как вы сейчас пытаетесь, и он будет создан.
Итак, чтобы обойти это, сначала удалите дубликаты с помощью следующей процедуры:
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})
Затем дополнительные вставки, содержащие повторяющиеся данные, не будут вставлены и будет записана соответствующая ошибка.
Наконец, обратите внимание, что "dropDups" является/не очень элегантным решением для удаления повторяющихся данных. Вы действительно хотите что-то с большим контролем, как показано выше.
Для второй части вместо использования .insert()
используйте метод .update()
. У этого есть опция "upsert"
$collection->update(
array( "uid" => 1, "sid" => 1 ),
array( '$set' => $someData ),
array( 'upsert' => true )
);
Таким образом, "найденные" документы "изменены", а не найденные документы "вставлены". Также см. $setOnInsert
, чтобы создать только определенные данные, когда документ фактически вставлен, а не когда он изменен.
Для вашей конкретной попытки правильный синтаксис .update()
- это три аргумента. "запрос", "обновление" и "параметры":
$collection->update(
array( "uid" => 1, "sid" => 1 ),
array(
'$set' => array( "field" => "this" ),
'$inc' => array( "counter" => 1 ),
'$setOnInsert' => array( "newField" => "another" )
),
array( "upsert" => true )
);
Ни одна из операций обновления не разрешает "доступ к одному и тому же пути", как используется в другой операции обновления в этом разделе "Обновление".