Обновление до сегментированного MongoDB с использованием полного ключа сегментов mgo Error должно находиться в объекте обновления для сбора:

Используя 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). а скорость - это абсолютно приоритет, поскольку я имею дело с десятками тысяч событий в секунду.

Я подхожу к тому моменту, когда чувствую, что перепробовал все мысли, которые только мог придумать, и был бы признателен за свежий взгляд, пытающийся помочь мне понять, что происходит, поэтому любая помощь будет принята с благодарностью.


person Verran    schedule 21.01.2014    source источник


Ответы (1)


Тип mgo.Change специфичен для Query.Apply, который запускает MongoDB findAndModify и сразу же внесет любые из поддерживаемых изменений. С другой стороны, метод Upsert принимает документ модификации, который будет непосредственно предоставлен mgo / bson для маршаллинга. Эти документы модификации имеют один и тот же формат вне зависимости от того, предоставляете ли вы их через Query.Apply (в поле Update mgo.Change) или через коллекцию .Upsert или Collection.Update.

Итак, наблюдаемая ошибка вызвана тем, что он пытается использовать mgo.Change как простую структуру для вставки (другими словами, документ с ключами «returnnew» и т. Д.), Что определенно не то, что вам нужно. Например, предоставленная вами команда оболочки эквивалентна прямому переводу с помощью mgo:

type M map[string]interface{}
err := collection.Upsert(
    M{
        "_id": "98364_2013-12-11",
        "ci":  "16326",
        "dt":  "2013-12-11",
        "zi":  "98364",
    },
    M{
        "$setOnInsert": M{"ci": "16326", "dt": "2013-12-11", "zi": "98364"},
        "$inc":         M{"test": 1},
    },
)

Это все еще не работает, но по другой причине. Как указано в сообщении об ошибке, сервер пытается установить ключ осколка во второй раз. Обратите внимание, что операция upsert будет использовать поля, указанные в документе запроса, и объединить как документ запроса и документ модификации, чтобы создать окончательный документ для вставки. Это означает, что поля ключей сегментов в документе $setOnInsert избыточны с полями ключей сегментов в документе запроса.

Я улучшу документацию в этой области, чтобы уменьшить вероятность того, что люди запутаются при использовании mgo.Change. Извините за неприятности.

person Gustavo Niemeyer    schedule 21.01.2014