[Mongoose] index が未作成な field を sort に指定して stream で取得すると default batchSize だけ処理して正常終了するので困った
Mongoose で index が作成されていない field を sort に指定して stream で取得すると、 default batchSize の 1000 件だけ処理して正常終了するので困った話をご紹介します。
find() で全件一括取得すると callback の第一引数 err には値は入らず、配列の末尾の要素に $err, code が含まれていました。
User.find().sort({
createdAt: -1
}).setOptions({
noCursorTimeout: true
}).exec(function(err, docs) {
console.log(err);
console.log(docs.length);
console.log(docs[docs.length - 1]);
/**
以下、console.log の出力結果
null
1001
{ '$err': 'getMore runner error: Overflow sort stage buffered data usage of 33555763 bytes exceeds internal limit of 33554432 bytes',
code: 17406,
...
**/
});
stram() で取得する場合も同じで、最後に取得した document に $err, code が含まれていました。
var stream = User.find()
.sort({ createdAt: -1 })
.setOptions({ noCursorTimeout: true })
.stream();
stream.on('data', function(user){
/**
default batchSize 1000 件だけ取得して、1001 件目に $err, code を含むデータを取得して、正常終了する
{ '$err': 'getMore runner error: Overflow sort stage buffered data usage of 33555763 bytes exceeds internal limit of 33554432 bytes',
code: 17406,
...
**/
});
stream.on('error', function(err){
// エラーイベントは呼び出されない
});
index が作成されていないのが元々の問題なので、index 作成すれば解決します。
User.path('createdAt').index(true);
index size が気になるので作成したくないという場合は、default で用意されている _id を sort に指定する対応でもいいと思います。
User.find().sort({
_id: -1
}).setOptions({
noCursorTimeout: true
}).exec(function(err, docs) {});
document が 1000 件しか取得できてないことに気付かない限り、エラーが発生していることに気付けないので Mongoose のエラーハンドリングの実装が微妙なのでは…