2014-04-18 130 views
1

我在嘗試根據mongodb上的另一個查詢的結果進行查詢時遇到問題。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.send結果集陣列已加入所有的值之後。

我已經嘗試了一些其他的方式來做到這一點,但事情是,當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)); 
    }); 
}); 

回答

1

你在你的問題更新的解決方案一般是罰款,如使用$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; 
     }    
    }); 
}); 
2

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)); 
       }); 
     }); 
+0

是啊,這其實是我想通了太多。那麼我想沒有其他的方式了。感謝您的回答! – lascort

+0

你可以使用遞歸,但是你會再次查詢mongodb。 – Sumeet