MongoDB 用のLabix mgo APIを使用して、シャード コレクションに対してインクリメント操作を実行しようとしています。通常の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 を通過するときにエラーが発生することがわかったので、非常に厳密に制御しようとしましたbson.D に切り替えることで、mgo.Change 構造体に渡されるドキュメントの順序:
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)
}
この時点で、変更オブジェクトを印刷すると、 Mongo's documentation[{Update [{$setOnInsert [{_id 11635_2013-12-11} {ci 3599} {dt 2013-12-11} {zi 11635}]} {$inc 0xc21dd9d8d0}]} {Upsert true}]
に従って正確に正しい順序で変更オブジェクトとして渡す必要があると思いますが、それでも同じエラーが発生します。full shard key must be in update object for collection: db.collection
使用collection.Find({_id: ... }).Apply(change, ...)
は可能な代替手段であり、使用すると適切に機能することを認識していますが、シャードされていないコレクションでのテストでは、Upsert (または更新) 関数を使用してパフォーマンスが大幅に向上することを確認しました (約 20 倍高速)。私は毎秒何万ものイベントを扱っているので、速度は絶対に優先事項です。
考えられる限りのことを試してみたような気がするところまで来ており、何が起こっているのかを理解するのを助けようとしている新鮮な目のセットに感謝しているので、どんな助けも感謝します.