Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/node.js/40.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Node.js Monogo聚合查询在服务器上花费的时间太长_Node.js_Mongodb_Aggregation Framework - Fatal编程技术网

Node.js Monogo聚合查询在服务器上花费的时间太长

Node.js Monogo聚合查询在服务器上花费的时间太长,node.js,mongodb,aggregation-framework,Node.js,Mongodb,Aggregation Framework,我试图在mongo中使用聚合框架来进行一些数据统计。我正在使用的查询,在本地运行几乎不需要一分钟,但当我在服务器上运行相同的查询时,它不会给出响应,并且在持续等待太长时间后,我不得不取消它,请任何人建议为什么会发生这种情况 var orderIds = db.delivery.find({"status":"DELIVERED"}).map(function(o) { return o.order }); var userIds = db.order.aggregate([{

我试图在mongo中使用聚合框架来进行一些数据统计。我正在使用的查询,在本地运行几乎不需要一分钟,但当我在服务器上运行相同的查询时,它不会给出响应,并且在持续等待太长时间后,我不得不取消它,请任何人建议为什么会发生这种情况

var orderIds = db.delivery.find({"status":"DELIVERED"}).map(function(o) {
    return o.order 
}); 

var userIds =  db.order.aggregate([{
    $match : { _id : { $in : orderIds } }
}, {
    $group: { _id : "$customer" }
}]).map(function(u) { return u._id });

var userstats = db.order.aggregate([{
    $sort : { customer : 1, dateCreated : 1 }
}, {
    $match : { status : "DELIVERED", customer : {  $in : userIds } }
}, { 
    $group: {
        _id : "$customer", orders : { $sum : 1 }, 
        firstOrderDate : { $first : "$dateCreated" },
        lastOrderDate : { $last : "$dateCreated" }
    }
}]);

userstats.forEach(function(x) { 
    db.user.update({ _id : x._id }, {
        $set : { 
            totalOrders : x.orders,
            firstOrderDate : x.firstOrderDate,
            lastOrderDate : x.lastOrderDate
        }
    })
})

我不确定,但在服务器上不是应该更快吗,但是它不能给出输出。

我建议您将
$match
作为管道中的第一个操作,因为
$match
操作符只能使用聚合管道中的第一个索引:

var userstats = db.order.aggregate([{
    $match : {
        status :"DELIVERED", 
        customer : { $in : userIds }
    }
}, {
    $sort : {
        customer : 1,
        dateCreated : 1
    }
}, { 
    $group : {  
        _id : "$customer",
        orders : { $sum : 1 }, 
        firstOrderDate: { $first : "$dateCreated" },
        lastOrderDate : { $last:"$dateCreated" }
    }
}]);
如果尚未定义索引,还应在
状态
客户
上添加索引:

db.delivery.createIndex({status:1,customer:1})

为了加快这个过程,您可以通过几种方式重构您的操作。 第一种方法是消除不必要的管道操作,如操作符,该操作符可以替换为管道中的操作符

其次,使用API,这将提高更新操作的性能,尤其是在处理大型集合时,因为它们将批量(例如,批量大小为500)向服务器发送操作,而不是向服务器发送每个请求(正如您当前在
forEach()
循环中对update语句所做的那样)

考虑以下重构操作:

var orderIds = db.delivery.find({"status": "DELIVERED"}).map(function(d){return d.order;}),
    counter = 0,
    bulk = db.user.initializeUnorderedBulkOp();

var userstatsCursor = db.orders.aggregate([
    { "$match": { "_id": { "$in": orderIds } } },
    { 
        "$group": { 
            "_id": "$customer", 
            "orders": { "$sum": 1 },
            "firstOrderDate": { "$min": "$dateCreated" },
            "lastOrderDate":{ "$max": "$dateCreated" } } 
        } 
    }
]);

userstatsCursor.forEach(function (x){
    bulk.find({ "_id": x._id }).updateOne({ 
        "$set": { 
            "totalOrders": x.orders,
            "firstOrderDate": x.firstOrderDate,
            "lastOrderDate": x.lastOrderDate
        }
    });

    counter++;
    if (counter % 500 == 0) {
        bulk.execute(); // Execute per 500 operations and 
        // re-initialize every 500 update statements
        bulk = db.user.initializeUnorderedBulkOp();
    }
});

// Clean up remaining operations in queue
if (counter % 500 != 0) { bulk.execute(); }

这个解决方案看起来不错,我可以看到很多新的东西,但是查询在某种程度上抛出了语法错误“Unexpected token}”@user29578有一个打字错误,我在更新的答案中删除了管道数组之前的一个额外的右括号。请再试一次。嗨,chridam,我收到了这个错误2016-02-14T02:32:33.615+0530 TypeError:Object函数(){return new Bulk(this,false);}在Object.DBQuery.forEach没有方法“find”(shell):1:436(src/mongo/shell/query.js:281:9)位于(shell):1:409@user29578您使用的是哪个MongoDB版本,您尝试了哪种方法?我使用的是2.7.2,我尝试从您的答案运行相同的查询,但它在批量查找方法时抛出此错误,不知道为什么会有此帮助:)