読者です 読者をやめる 読者になる 読者になる

S.F. Page

Programming,Music,etc...

Dateのserialize/deserializeは工夫が必要 - NeDBのserializeメソッドにおけるちょっとしたHack(2)

NeDB

昨日の記事の続き。

blog.sfpgmr.net

ちょっとしたHackというのは以下のコードなのだが、DateJSON.stringifyするときになぜreplacerでこのようなことをしなければならないのかということについてちょっとメモっておく。

    // Hackish way of checking if object is Date (this way it works between execution contexts in node-webkit).
    // We can't use value directly because for dates it is already string in this function (date.toJSON was already called), so we use this
    if (typeof this[k].getTime === 'function') { return { $$date: this[k].getTime() }; }

こうしている理由であるが、2つあって

  1. nw.js中の実行コンテキストでも動作させるため
  2. Datestringifyした結果はシリアライズされた文字列(ISO-8601)なので、このままだとJSON.parseしたときにDateに復元されないから

である。この2.については以下に詳細に説明されている。

JSON.stringify/parseは困ったもんだ。 - IT-Walker on hatena

上で書かれている困った仕様というのは2つある。

  1. JSON文字列からDateを復元できない。
  2. Datestringifyすると、ブラウザによって実行結果が異なる。

1.の理由はさておき、実質的にはこの2つの仕様によって、ちょっとしたHackが必要なのだ。 ECMA Script 2015のDate.toJSON仕様を見たけど、この仕様は変わっていないようである。 ただ形式がISO-8601ではなく拡張ISO-8601だと書いてあったのがちょっと気になる。というのもこの値をJSON-LDフォーマットで保存しようとしたとき、schema.orgのDate型はISO-8601形式なので、変換が必要になりそうな気がしたからだ。拡張ISO-8601とISO-8601の違いはミリ秒表記があるかないかである。でそのあたりを調べたらISO-8601形式はBasicとExtendという形式があると書いてあって変換不要だと分かった。よかった。

今のところ安全なのはミリ秒の数値に変換しておくことだ。なのでNeDBはミリ秒に変換して、さらにこの数値がDateだとわかるように{$$date:(ミリ秒)}というオブジェクトで格納しているのである。

で、NeDBがserializeした結果なのだけれども、普通のテキストファイルで保存される。1つのレコードはテキストの1行で保存される、つまり行数=レコード数である。またserializeされた結果はJSON形式ではない。汎用的な意味合いでちょっと残念だが、おそらくこれはパフォーマンス面で熟考の末こうなったと思われるので、しょうがないかなと思う。