2

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 倍高速)。私は毎秒何万ものイベントを扱っているので、速度は絶対に優先事項です。

考えられる限りのことを試してみたような気がするところまで来ており、何が起こっているのかを理解するのを助けようとしている新鮮な目のセットに感謝しているので、どんな助けも感謝します.

4

1 に答える 1

3

mgo.Changeタイプは、MongoDB findAndModifyコマンドを実行し、サポートされている変更を一度に実行するQuery.Applyメソッドに固有です。一方、 Upsertメソッドは、マーシャリングのために mgo/bson に直接提供される変更ドキュメントを受け取ります。これらの変更ドキュメントは、Query.Apply ( mgo.Change のフィールド)を介して提供するか、Collection.UpsertまたはCollection.Updateメソッドを介して提供するかに関係なく、同じ形式になります。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。ご迷惑おかけして申し訳ありません。

于 2014-01-21T23:06:45.687 に答える