Используя Labix mgo API для MongoDB, я пытаюсь выполнить операцию увеличения на сегментированном коллекция. Я могу сделать это нормально для необработанной коллекции, используя обычную структуру mgo.Change, но когда я пытаюсь сделать это для сегментированной коллекции, я получаю сообщение об ошибке: full shard key must be in update object for collection: db_name.collection_name
Исходный код, работающий с нерасчлененной коллекцией, выглядит так:
change := mgo.Change{
ReturnNew: true,
Upsert: true,
Update: bson.M{
"$setOnInsert": bson.M{
"ci": r.Ci,
"dt": r.Dt,
"zi": r.Zi,
},
"$inc": &data,
},
}
_, err := collection.Upsert(bson.M{"_id": id, "ci": r.Ci, "dt": r.Dt, "zi": r.Zi}, change); if err != nil {
log.Println("FAILURE", err)
}
Однако, когда я переключаюсь на сегментированную коллекцию, разделенную на ключ {ci: 1, dt: 1, zi: 1}
, я получаю указанную выше ошибку.
Пытаясь отладить, я попытался выяснить, что происходит за кулисами с mgo, и попытался выполнить вставку непосредственно в терминал mongo.
db.collection.update({ "_id" : "98364_2013-12-11", "ci" : "16326", "dt" : "2013-12-11", "zi" : "98364"}, {$setOnInsert: { "ci" : "16326", "dt" : "2013-12-11", "zi" : "98364"} , $inc: {test :1}}, { upsert: true });
Однако это вызвало у меня отдельную ошибку: Can't modify shard key's value. field: ci: "16326" collection: db.collection
Это то, что, я думаю, мне придется выяснить, как только я выясню свою исходную ошибку, но мне кажется странным, что эта ошибка возникает с помощью команды $ setOnInsert, поскольку она не предполагается чтобы изменить значение, просто установите его при начальной вставке. Все ошибки исчезают, когда я вырезаю часть команды $ setOnInsert, но мне нужен способ убедиться, что эти значения установлены, потому что они будут важны в запросах, которые я пишу, чтобы вернуть данные.
Вернемся к моей основной проблеме: я обнаружил, что когда я изменил порядок обновления и обновления документов при взаимодействии с терминалом MongoDB, я получил ошибку, которую получаю, когда прохожу через mgo, поэтому я попытался очень строго контролировать порядок документов, передаваемых в структуре mgo.Change путем переключения на bson.D:
change := bson.D{
{
"Update",
bson.D{
{"$setOnInsert", bson.D{
{"_id", id},
{"ci", r.Ci},
{"dt", r.Dt},
{"zi", r.Zi},
},
},
{"$inc", &data},
},
},
{
"Upsert",
true,
},
}
log.Println(change)
err := collection.Update(bson.D{{"_id", id},{ "ci", r.Ci},{ "dt", r.Dt}, {"zi", r.Zi}},change); if err != nil {
log.Println("FAILURE", err)
}
На этом этапе печать объекта изменения дает: [{Update [{$setOnInsert [{_id 11635_2013-12-11} {ci 3599} {dt 2013-12-11} {zi 11635}]} {$inc 0xc21dd9d8d0}]} {Upsert true}]
, который я считаю именно тем, что я должен передать в качестве объекта изменения в точном правильном порядке согласно документация Mongo, но я все равно получаю ту же ошибку full shard key must be in update object for collection: db.collection
.
Я понимаю, что использование collection.Find({_id: ... }).Apply(change, ...)
- возможная альтернатива, и она работает правильно, когда я ее использую, но в моем тестировании на необработанных коллекциях я видел гораздо более высокую производительность (примерно в 20 раз быстрее) с помощью функций Upsert (или Update). а скорость - это абсолютно приоритет, поскольку я имею дело с десятками тысяч событий в секунду.
Я подхожу к тому моменту, когда чувствую, что перепробовал все мысли, которые только мог придумать, и был бы признателен за свежий взгляд, пытающийся помочь мне понять, что происходит, поэтому любая помощь будет принята с благодарностью.