[MongoDB] exception: can’t convert from BSON type EOO to Date の解決方法

MongoDB の aggregate で値が入ってない Date field に $year, $month を適用したところ exception: can’t convert from BSON type EOO to Date というエラーが発生して、解決した内容をご紹介します。

MongoDB | モンゴディービー

MongoDB データの前提

MongoDB に以下のようなデータが保存されている users collection があるとします。

// createdAt field が有る document
db.users.save( { name: 'hoge', createdAt: ISODate('2017-01-01') })
db.users.save( { name: 'fuga', createdAt: ISODate('2017-02-02') })
db.users.save( { name: 'mogu', createdAt: ISODate('2017-02-20') })
 
// createdAt field が無い document
db.users.save( { name: 'spam })

can’t convert from BSON type EOO to Date の解決方法

エラーが発生するクエリ

createdAt field に値が保存されていないにも関わらず $year, $month オペレーターを適用するとエラーが発生します。

db.users.aggregate({
  $project: {
    createdAt: 1
  }
}, {
  $group: {
    _id: {
      year: {
        $year: "$createdAt"
      },
      month: {
        $month: "$createdAt"
      }
    },
    count: {
      $sum: 1
    }
  }
});
 
// 以下、実行結果
assert: command failed: {
	"ok" : 0,
	"errmsg" : "can't convert from BSON type EOO to Date",
	"code" : 16006
} : aggregate failed
_getErrorWithCode@src/mongo/shell/utils.js:25:13
doassert@src/mongo/shell/assert.js:16:14
assert.commandWorked@src/mongo/shell/assert.js:290:5
DBCollection.prototype.aggregate@src/mongo/shell/collection.js:1312:5
@(shell):1:1
 
2018-02-02T23:04:34.794+0900 E QUERY    [thread1] Error: command failed: {
	"ok" : 0,
	"errmsg" : "can't convert from BSON type EOO to Date",
	"code" : 16006
} : aggregate failed :
_getErrorWithCode@src/mongo/shell/utils.js:25:13
doassert@src/mongo/shell/assert.js:16:14
assert.commandWorked@src/mongo/shell/assert.js:290:5
DBCollection.prototype.aggregate@src/mongo/shell/collection.js:1312:5
@(shell):1:1

エラーが発生しないクエリ

createdAt が Date Type なことをチェックするために $type: 9 を利用します。少し雑に比較するなら $ne: null や $exists: true なども使えます。

$year, $month など Date な値が渡ってくることを期待したオペレーターを使う場合は、$match で条件指定しておきましょうという話ですね。

db.users.aggregate({
  $match: {
    createdAt: {
      $type: 9 // 雑に $ne: null や $exists: true も使える
    }
  }
}, {
  $project: {
    createdAt: 1
  }
}, {
  $group: {
    _id: {
      year: {
        $year: "$createdAt"
      },
      month: {
        $month: "$createdAt"
      }
    },
    count: {
      $sum: 1
    }
  }
});
 
// 以下、実行結果
{ "_id" : { "year" : 2017, "month" : 2 }, "count" : 2 }
{ "_id" : { "year" : 2017, "month" : 1 }, "count" : 1 }

以上、MongoDB の aggregate メソッドでエラーに遭遇した現場からお送りしました。

参考情報