SPACEKEY

Technical Memorandum

MongoDBのObjectId

November 21, 2013

MongoDBをC#で操作しているシステムで、あるオブジェクトをJSON.netでJSONにシリアライズしてやりとりするようなことをしていました。

もともとBSONのままやりとりしていたんですが、ちょっと別の環境とデータを連係させるのにJSONの方が都合がいいこともあり、C#のシステムの外とやりとりする部分をJSON.netでシリアライズ/デシリアライズするように書き直しておりました。

これ自体大して難しいことではなかったのですが、動かしてみるとどうしてもObjectIdが全部0(Empty値)になってしまうのです。 JSONの中身をよくよく見てみると、

  \"_id\":
    {
      \"Timestamp\":1385017265,
      \"Machine\":697085,
      \"Pid\":9400,
      \"Increment\":11974837,
      \"CreationTime\":\"\\/Date(1385017265000)\\/\"
    }

なんかこのようなことに……これってObjectIdを生成する元のパラメータですね。 JSON.netのJsonConvert.SerializeObjectで文字列にするとこうなってしまいます。これがそのまま外に出てからDeserializeしてもちゃんと元に戻らないと言うことですね。

そのオブジェクトは、中身にListとかその中身に別のドキュメントがネストされていたりとちょっと複雑な構成になっていて、もしかしたらそのせいかも……と思って、ごくごくシンプルなネストされたドキュメントなどを作ってシリアライズするような検証をしていたのですが、どんな複雑な構成にしてもちゃんとObjectIdが普通に出力されるのです。 さらに、同じデータベースからデータを抽出して文字列にしてみてもやっぱりちゃんと出る。 でも、作っているシステムではどうやっても、ObjectIdが文字列で出ない……

相当悩んだのですが、結局原因は「JSON.netのバージョンが低かった!」と言うことでした。 もう、情けないやらなにやら……

何でこうなったかというと、作っているシステムには、JSON.netの4.0なにがしかが入っていました。 なんか別のパッケージを入れたときに一緒に入ったと思われるのですが、なんか別のプロジェクトに入れたのを勘違いでもしたのか、新しいものを入れたんだと思ってそのまま使っておりました。 そして、検証用のプログラムの方は、全く新しいプロジェクトでパッケージを新しくセットして始めたので、5.0.8が入りました。

いやー、つまらないことではまりました。

で、あとはおまけなんですが、C#でMongoDBのドキュメント用にクラスを作る場合、これまでObjectIdを格納するフィールドには、MongoDB.Bson.ObjectId型のフィールドを使っていたのですが、これをそのままにしておくとJSONからデシリアライズする際にキャストできないって叱られるようになります。

なんかAttributes(?)なんかで変換するアダプタを指定して……みたいな方法も見たんですが、結局……

  • using MongoDB.Bson.Serialization.Attributes; する
  • idの部分をstring型にする
  • [BsonRepresentation(BsonType.ObjectId)]をつける
  • ドキュメントのidになるようなものには、[BsonId]もつけておけばいいかな という方法で、プログラム中では全部stringで扱うように変更しました。

あとなんか日付の部分も若干何か気になることもないでもないですねぇ。