BSONとundefined
JavaScript, MongoDBBSON とは
BSON (Binary JSON) Serialization
Binary JSON の略で、その名の通り Binary の JSON みたいな何か。
JSON の上位種でもあり、バイト配列や Date 型を持てたりもする。
主に MongoDB で使う。
undefined とは
未定義の変数とか未定義を表すために使われることがあったりするよくわからないプリミティブ値。
foo.ts
let foo
let bar = undefined
JSON と undefined
まず、JSON の場合…
RFC 8259 の項目を読む限り、JSON の値に undefined
を含めることはできない。
JSON.stringify では、値が undefined
の Key を省略するようになっている。
foo.ts
const foo = {
hoge: undefined,
fuga: void 0,
}
console.log(JSON.stringify(foo)) // "{}"
foo.hoge = 'bar'
console.log(JSON.stringify(foo)) // "{"hoge":"bar"}"
ただし、配列の中に含まれる undefined
は、null
に変換される。
foo.ts
const foo = ['hoge', undefined, 'bar']
JSON.stringify(foo) // "["hoge",null,"bar"]"
const baz = [,,]
JSON.stringify(baz) // "[null,null]"
BSON と undefined
BSON では null
になる。
以下のコードは、未定義、明示したもの、void 0
、配列内の undefined
な値を insert したもの。
console.log()
では配列内の値も含めて、全て null
に変換されていることがわかる。
mongo.ts
import mongodb from 'mongodb'
const MongoClient = mongodb.MongoClient
const URL = 'mongodb://127.0.0.1:27017/myDB'
const DB_NAME = 'mydb'
const COLLECTION_NAME = 'foo'
const client = new MongoClient(URL, {
useNewUrlParser: true,
})
const connect = async () => {
try {
await client.connect()
const collection = client.db(DB_NAME).collection(COLLECTION_NAME)
let hoge
await collection.insertOne({
hoge,
fuga: undefined,
piyo: void 0,
baz: [, undefined, void 0],
})
const itemList = await collection.find().toArray()
console.log(itemList)
// { hoge: null, fuga: null, piyo: null, baz: [ null, null, null ]}
} catch (error) {}
client.close()
}
connect()
MongoDB Node.js Driver ではこれを回避するために、ignoreUndefined
オプションを指定できる。
ignoreUndefined
が true の場合、JSON.stringify()
のように undefined
のプロパティを無視する。
mongo.ts
// 略
const client = new MongoClient(URL, {
useNewUrlParser: true,
ignoreUndefined: true,
})
// 略
console.log(itemList)
// { baz: [ null, null, null ] }
// 略
BSON と undefined 2
しかし、spec をみる限りだと、どうやら undefined
自体は受け入れている。
例えば、以下のような insert query を実行すると
mongodb
db.foo.insert({poge: undefined, puga: [void 0, , undefined]})
普通に入ってしまう。
mongodb
{
_id: 5e9afd45ff583d0116194c00,
poge: undefined,
puga: [ undefined, undefined, undefined ]
}
本当なのか。
BSON を JSON に Dump してみる。
shell
mongodump --port 27017 --db mydb
bsondump --outFile=foo.json foo.bson
この通り。
foo.json
{
"_id": {
"$oid": "5e9afd45ff583d0116194c00"
},
"poge": {
"$undefined": true
},
"puga": [
{
"$undefined": true
},
{
"$undefined": true
},
{
"$undefined": true
}
]
}
Deprecated だけど、MongoDB Node.js Driver でも一応読める。
mongo.ts
{
_id: 5e9afd45ff583d0116194c00,
poge: undefined,
puga: [ undefined, undefined, undefined ]
},
もともと、MongoDB は undefined
と null
を持ちながらも、Shell では両方を null
にしていた。
これが本当に未定義だった時に混乱するので、undefined
へデシリアライズするようになった。
という解釈をした。それに関する修正がこちら。