【问题标题】:Multiple queries inside mongodb querymongodb查询中的多个查询
【发布时间】:2014-04-18 19:48:16
【问题描述】:

我在尝试根据 mongodb 上另一个查询的结果进行查询时遇到问题。

我正在尝试进行初始查询,然后对第一个查询的每个结果进行另一个查询。我这样做的原因是因为我有两个不同的集合,我需要将一个集合中的一些数据与另一个集合的数据连接起来。在 SQL 世界中,我可以使用 JOIN 轻松完成此操作,但由于我在此使用 mongodb,我不能真正使用 JOIN,所以我猜想在第一个查询的回调函数中执行 for 循环将是可行的方法.

这是我正在使用的代码...

var resultSet = [];
db.get('busstopcollection').find({id_bus_stop: parseInt(req.body.busstopid)}, function(e, docs){
    if(e || docs.length === 0) {
        console.log("Sorry, wrong id.");
        return e;
    }
    for(var m=0; m<docs.length; m++){

        var auxRes = {};
        auxRes.id_bus = docs[m].id_bus;
        auxRes.id_bus_stop = docs[m].id_bus_stop;
        auxRes.coord_x = docs[m].coord_x;
        auxRes.coord_y = docs[m].coord_y;
        auxRes.id_bus_variation = docs[m].id_bus_variation;
        db.get('buscollection').find({id_bus: parseInt(docs[m].id_bus)}, function(e, busDocs){
            auxRes.s_origin_description = busDocs[0].s_origin_description;
            auxRes.s_destination_description = busDocs[0].id_destination_description;
            resultSet.push(auxRes);
        });
        res.send(JSON.stringify(resultSet));
    }
});

添加完所有值后,我需要res.sendresultSet 数组。

我尝试了其他一些方法,但问题是当到达res.send 行时,第二个查询根本没有完成。我也尝试在内部查询的回调中这样做,但我需要检查它是否是 for 循环中的最后一个,并且检查值 o m 不会这样做,因为它始终等于docs.length

据我所知,在 mongodb 中没有同步查询之类的东西,但也许我错了。

这样做的正确方法是什么?

编辑

我找到了解决方法,但我确信一定有更好的方法。这就是我的做法...

db.get('busstopcollection').find({id_bus_stop: parseInt(req.body.busstopid)}, function(e, docs){
    if(e || docs.length === 0) {
        console.log("Ha ocurrido un error, no existe esa parada");
        return e;
    }
    var busIDs = [];
    for(var m=0; m<docs.length; m++){
        busIDs.push(parseInt(docs[m].id_bus));
        var auxRes = {};
        auxRes.id_bus = docs[m].id_bus;
        auxRes.id_bus_stop = docs[m].id_bus_stop;
        auxRes.coord_x = docs[m].coord_x;
        auxRes.coord_y = docs[m].coord_y;
        auxRes.id_bus_variation = docs[m].id_bus_variation;
        resultSet.push(auxRes);
    }
    db.get('buscollection').find({id_bus: {$in: busIDs}}, function(e, busDocs){
        for(var n = 0; n<busDocs.length; n++){
            for(var k=0; k<resultSet.length; k++){
                if(resultSet[k].id_bus == busDocs[n].id_bus){
                    resultSet[k].s_origin_description = busDocs[n].s_origin_description;
                    resultSet[k].s_destination_description = busDocs[n].id_destination_description;
                }
            }
        }
        res.send(JSON.stringify(resultSet));
    });
});

【问题讨论】:

    标签: node.js mongodb synchronous nosql


    【解决方案1】:

    Node.js 的行为是异步的,程序员必须在编写代码时考虑到这种行为。使用回调或承诺或流控制库。在你的程序中,你 已将 mongo 查询放入循环中,这是一种不好的查询方法。相反,如果查询多次,请使用 $in 运算符。它将优化您的代码性能和 也解决了您的响应发送问题。

    var resultSet = [];
            db.get('busstopcollection').find({id_bus_stop: parseInt(req.body.busstopid)}, function(e, docs){
                if(e || docs.length === 0) {
                    console.log("Sorry, wrong id.");
                    return e;
                }
                var bus_ids = [];
                for(var m=0; m<docs.length; m++){
                    var auxRes = {};
                    auxRes.id_bus = docs[m].id_bus; 
                    bus_ids.push(parseInt(docs[m].id_bus)); // collect all ids 
                    auxRes.id_bus_stop = docs[m].id_bus_stop;
                    auxRes.coord_x = docs[m].coord_x;
                    auxRes.coord_y = docs[m].coord_y;               
                    auxRes.id_bus_variation = docs[m].id_bus_variation;
                    resultSet.push(auxRes);         
    
                }
                // Query at one time for all document 
                db.get('buscollection').find({id_bus: {$in : bus_ids}}).toArray( function(e, busDocs){
                        // Now find and merge in one go
                        busDocs.forEach(function(eachBusDoc){
                            for(var i=0,len = resultSet.length;i< len;i++){
                                if(resultSet[i].id_bus == busDocs.id_bus ){
                                    resultSet[i].s_origin_description = eachBusDoc.s_origin_description;
                                    resultSet[i].s_destination_description = eachBusDoc.id_destination_description;
                                }
                            }
                        });             
                           res.send(JSON.stringify(resultSet));
                    });
            });
    

    【讨论】:

    • 是的,这实际上也是我想出来的。我想那时没有其他方法可以做到这一点。感谢您的回答!
    • 您可以使用递归,但您将再次查询 mongodb 多次。
    【解决方案2】:

    您在问题中更新后的解决方案通常没问题,因为使用 $in 是获取一组结果的绝佳方式(您需要确保已为 id_bus 属性编制索引)。

    这里有一些调整(有一些清理和优化):

    db.get('busstopcollection')
      .find({id_bus_stop: parseInt(req.body.busstopid)}).toArray(function(e, docs){
        var auxById = {};   // store a dictionary of all the results for later
        if(e || docs === null || docs.length === 0) {
            console.log("Ha ocurrido un error, no existe esa parada");
            return e;
        }
        var busIDs = [];
        docs.forEach(function(doc) {
            busIDs.push(parseInt(doc.id_bus));
            // consider just using the doc directly rather than copying each property 
            // especially if you're not manipulating any of the data as it passes
            var auxRes = {        
                id_bus : doc.id_bus,
                id_bus_stop : doc.id_bus_stop,
                coord_x : doc.coord_x,
                coord_y : doc.coord_y,
                id_bus_variation : doc.id_bus_variation
            };
            // you could just use each doc directly ...
            // var auxRes = doc; ??
            // ** importantly, store off the id_bus for each one so you can
            // ** avoid a costly loop trying to match an id below.
            auxById[doc.id_bus] = auxRes;
            resultSet.push(auxRes);
        });
        // might want to consider using a cursor ... here's an example
        db.get('buscollection')
            .find({id_bus: {$in: busIDs}}).each(function(e, busDoc){
            // the last item in the cursor will be null
            if (busDoc === null) {
                res.send(JSON.stringify(resultSet)); 
                return;
            }
            var res = auxById[busDoc.id_bus];
            if (res) {   // did we find it in our dictionary of results?
               // yes, we did == copy the necessary field data
               res.s_origin_description = busDoc.s_origin_description;
               res.s_destination_description = busDoc.id_destination_description;
            }            
        });
    });
    

    【讨论】:

      猜你喜欢
      • 2014-12-13
      • 2012-05-11
      • 1970-01-01
      • 2020-12-15
      • 2015-03-01
      • 1970-01-01
      • 1970-01-01
      • 2018-04-07
      • 1970-01-01
      相关资源
      最近更新 更多