mongoDBで日付を扱うときの注意点

mongoDBに入れていたデータを日付単位でaggregateを使って集計しようとしたら、

can’t convert from BSON type String to Date

みたいなエラーでハマってしまったので、いろいろ試行錯誤したときのメモ。

日付を文字列として格納するとaggregateで日付として扱えない

日付を文字列としてmongoDBに格納していたのですが、aggregateで期間指定しようとしてもエラーになるうまく行きませんでした。

> db.test.insert({"date":"Sat Aug 22 21:03:40 GMT+09:00 2015"});
> db.test.aggregate({$project:{year:{$year:"$date"}}})
assert: command failed: {
 "errmsg" : "exception: can't convert from BSON type String to Date",
...

ちゃんとDate型(type 9)で格納する必要があるそうです。
下の例でいうと「ISODate(“2015-10-10T12:24:19.508Z”)」となっているとDate型です。他は文字列として入っているのでNG。

> db.test.insert({"date":new Date("Sat Oct 10 21:24:19 GMT+09:00 2015")});
> db.test.insert({"date":"Sat Aug 22 21:03:40 GMT+09:00 2015"});
> db.test.insert({"date":"2015-08-26T12:03:40Z"});
> db.test.find()
{ "_id" : ObjectId("561903732489c6fd1a587f1c"), "date" : ISODate("2015-10-10T12:24:19Z") }
{ "_id" : ObjectId("561903b32489c6fd1a587f1d"), "date" : "Sat Aug 22 21:03:40 GMT+09:00 2015" }
{ "_id" : ObjectId("5619140b5c1d5c59181ae41a"), "date" : "2015-08-26T12:03:40Z" }

> db.test.aggregate({$match: {"date":{$type:9}}},{$project:{year:{$year:"$date"}}})
{ "_id" : ObjectId("561903732489c6fd1a587f1c"), "year" : 2015 }

日付をISODate(標準時)として扱うので、日本時間に変換が必要

MongoDBから日付を取り出すと標準時になっているので、日本時間に直すには9時間追加する必要があります。

nodejsから日付をInsertするときの扱われかた

mongoozeだとスキーマ定義できるので型を指定できますが、普通のドライバだと型指定ができなさそうなので、書き方によって文字列として格納されるので注意が必要。

var MongoClient = require('mongodb').MongoClient;
var MONGODB_URI = 'mongodb://xxx:27017/test';
var db;

MongoClient.connect(MONGODB_URI, function(err, database) {
  if(err){
  }
  db = database;
});

var coll = db.collection('test');

//↓文字列として格納される
coll.insert({"date":"Sat Aug 22 21:03:40 GMT+09:00 2015"});
//↓日付型として格納される
coll.insert({"date":new Date("Sat Aug 22 21:03:40 GMT+09:00 2015")});

//↓文字列として格納される
tmp = JSON.parse('{"date":"Sat Aug 23 21:03:40 GMT+09:00 2015"}')
coll.insert(tmp);

//↓日付型として格納される
tmp = JSON.parse('{"date":"Sat Aug 23 21:03:40 GMT+09:00 2015"}')
tmp.date = new Date(tmp.date);
coll.insert(tmp);