2014-01-21 5 views
1

Используя команду Labix mgo API для MongoDB, я пытаюсь выполнить операцию инкремента в собранной коллекции. Я могу сделать это просто отлично в неподготовленной коллекции, используя обычную структуру mgo.Change, но когда я пытаюсь сделать это в собранной коллекции, я получаю ошибку: full shard key must be in update object for collection: db_name.collection_nameУсовершенствование для отложенного MongoDB с использованием mgo Error «полный ключ осколка должен находиться в объекте обновления для сбора: ...»

Исходный код, который работает на un -sharded коллекция выглядит следующим образом:

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

Однако при переходе к sharded коллекции, sharded на ключевом {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's documentation, но я все равно получаю то же самое full shard key must be in update object for collection: db.collection.

Я понимаю, что использование collection.Find({_id: ... }).Apply(change, ...) является возможной альтернативой, и оно работает правильно, когда я его использовал, но при тестировании на незащищенных коллекциях я видел более высокую производительность (как в ~ 20 раз быстрее) с помощью Upsert (или Обновление), и скорость является абсолютно приоритетной, поскольку я имею дело с десятками тысяч событий в секунду.

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

ответ

2

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

Таким образом, наблюдаемая ошибка возникает из-за того, что она пытается использовать mgo.Change в качестве простой структуры для вставки (другими словами, документ с ключами «returnnew» и т. Д.), Что определенно не то, что вы хотите.Командная оболочка вы предоставили, например, эквивалентно прямой трансляции с МдО:

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 будет использовать поля, предоставленные в документе запроса, и merge both документ запроса и документ модификации для создания окончательного документа для вставки. Это означает, что поля ключа осколка в документе $setOnInsert избыточны с полями ключа осколка в документе запроса.

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