MongoDB查询大型集合

时间:2015-08-19 20:58:41

标签: javascript node.js mongodb mongoose meanjs

我有一个名为'价格'的MongoDB系列。我试图查询“开始日期”和“开始日期”之间的价格。和' endDate'。

该集合每10秒存储一次价格,但是当查询此集合以进行图形化时,每1-2分钟的价格非常重要。

我试图以两种不同的方式编写此查询:

方法1:使用{$ gte:startDate,$ lte:endDate}

 function getResultsInRange(startDate, endDate) {
    if(typeof startDate !== 'undefined' && typeof endDate !== 'undefined') {
        Price.find({timestamp: {$gte: startDate, $lte: endDate}}, 'price timestamp exchange')
        .sort('-timestamp')
        // .populate('exchange')
        .exec(function(err, prices) {
            if(err) {
                res.jsonp({'error': err});
            } else {
                console.log("Found: " + prices.length + " prices");
                res.jsonp(prices);
            }
        });

    }
}

此方法抛出以下错误:

{"error":{"name":"MongoError","$err":"Executor error: Overflow sort stage buffered data usage of 33554490 bytes exceeds internal limit of 33554432 bytes","code":17144}}

如果我删除了排序(' -timestamp")行,并再次运行此查询,则会出现以下错误:

GET /prices/graph/minute - - ms - -
FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - process out of memory

我也尝试在此查询中使用索引来尝试避免32MB的内存排序限制,但是还没有能够实现它。我想知道它是否是由问题造成的:

"The total size of an index entry, which can include structural overhead depending on the BSON type, must be less than 1024 bytes."

这里描述:(http://docs.mongodb.org/manual/reference/limits/#indexes

方法2:使用While循环查询每X分钟的最后价格(例如2)

function getResultsInRange(startDate, endDate) {
    if(typeof startDate !== 'undefined' && typeof endDate !== 'undefined') {

        var currentDate = startDate;
        currentDate.setSeconds(0);

        var priceData = {};

        while(currentDate < endDate) {                
            Price.findOne({'timestamp': {$lte: currentDate}}, 'price timestamp exchange')
            .sort('-timestamp')
            .exec(function(err, price) { 
                if(err) {
                    console.log('ERROR: ' + err);
                } else if (price !== null) {               
                    // PUSH DATA TO ARRAY HERE                        
                }
            });

            // Increment Current Date.
            currentDate.setMinutes(currentDate.getMinutes() + 2);
        }

        res.jsonp(priceData);
    }//end if startDate and endDate are defined (giving us a valid date range).
}// end getResultsInRange()

然而,这种方法不起作用,似乎对于循环的每次迭代&#39; currentDate&#39; =&#39; startDate&#39;所以它只是在“开始日期”之前查询数据库中记录的最后价格。

编辑:方法3:使用Stream() 我也尝试过使用.stream()。

 var query = Price.find({timestamp: {$gte: startDate, $lte: endDate}}, 'price timestamp exchange').populate('exchange').stream();
 query.on('data', function(price) {
     // ADD TO ARRAY
 }).on('error', function(err) {
     console.log("ERROR: " + err);
 }).on('close', function() {
     res.jsonp(priceData); 
 });

非常感谢任何帮助!

1 个答案:

答案 0 :(得分:0)

我想出了这个。

我设法通过向Mongoose Schema添加索引来使索引工作:

timestamp: {
    type: Date,
    index: true,
    default: Date.now
}, 

然后使用以下函数执行查询。

function getResultsInRange(startDate, endDate) {
    if(typeof startDate !== 'undefined' && typeof endDate !== 'undefined') {
        Price.find({timestamp: {$gte: startDate, $lte: endDate}}, 'price timestamp exchange')
        .sort('-timestamp')
        .populate('exchange')
        .exec(function(err, prices) {
            if(err) {
                res.jsonp({'error': err});
            } else {
                res.jsonp(prices);
            }
        });    
    }
}   

上述工作在startDate和endDate之间最多可以运行14天,尽管使用索引运行大约需要20秒。