1年くらい前に、MongoDBにJSONオブジェクトをドキュメントとして保存する方法について調べたことがあります。そのまま眠っていた短いメモを公開します。「最新の状況を確認してから」とも思ったのですが、そうするとメモは永久に眠ったままになりそうなので確認してません。という次第で、現状との食い違いがあるかもしれません。
まず、2010年に書いた記事「唐突に MongoDB の話」の「BSON」、「BSONとJSONの違い」という節で次の注意をしています。
BSONは名前も構造もJSONと似てますが、別物です。
BSONを「JSONのバイナリーフォーマット」と思うと大間違い。データモデルが違います。
そのとき指摘しておいたギャップは:
- BSONの数値は、「32-bit signed integer」、「64-bit signed integer」、「64-bit IEEE 754 floating point」の三種類がある。JSONでは、数値フォーマットの違いを区別する記法(例えば、1, 1L, 1.0 のような区別)はない。
- BSONのオブジェクトはフィールド(プロパティ)のシーケンスなので、フィールドの順序がある。一方、JSONオブジェクトの実現の多くでは、キーのあいだに順序がないハッシュ(連想配列)データを使っている。
他に問題になるかも知れない点:
- プロパティ名(フィールド名)にはドット('.')を入れられない。
- プロパティ名の先頭にドル記号('$')は使えない。
- プロパティ名の最大長は、UTF-8エンコーディングで255バイトである。
- 値の非存在を表すためにnullを使っている。
- ObjectIDは特別なデータである。
プロパティ名に使えない文字があるのはけっこう障害になるかもしれません。例えば、JSONではコメントが入れられないので、"$comment": "これはコメント." のようなプロパティで代用していたり、URIを "$ref" という名前のプロパティに入れたりしてました*1。こういう習慣とは衝突します。
「値の非存在がnull」とは、MongoDBの問い合わせオペレータで、{$exists: true} と {$ne: null} が同値なことから分かります。存在しないオブジェクトプロパティや配列項目には、あたかもnullが入っているように扱うのです。更新オペレータ $unset で配列項目を消すと、実際にはnullが代入されます。http://bsonspec.org/ を見ると、Undefinedというデータ型もある(あった)のですが deprecated です。
BSONを扱うライブラリでは、文字列やバイナリとな異なる ObjectID というネイティブ・データ型を用意していることが多いですが、JSONにはそんな特殊なデータ型はありません。ObjectIDを文字列としてエンコードする必要があります。
*1:[追記]これは僕の周辺でのローカルルールですが、ドル記号で始まるプロパティ名を特殊な用途に予約することは、比較的よく行われている気がします。[/追記]