Nodejs+mongodb联表查询问题

Nodejs+mongodb联表查询问题

我现在有两个表 一个question { “name” : “test”, “faq” : “faq”, “_id” : ObjectId(“521dac0e5a5be3f81e000002”), }

一个info { “name” : “test”, “imgUrl” : “./public/images/11.jpg”, "_id" : ObjectId(“521dac2b5a5be3f81e000004”) }

我的需求是,查询question中的name,然后还有知道name的头像地址,所以要二次查询info中imgUrl

mongodb.open(function(err, db){

if(err){

return callback(err);

}

//读取 users 集合

db.collection(‘question’, function(err, collection){

if(err){

mongodb.close();

return callback(err);

}

//查找用户名 name 值为 name文档

collection.find({hide:{$ne:false}}).limit(5).sort({time:-1}).toArray(function(err,items){

if(err) throw err;

//二次查询

db.collection('info', function(err, collection){

    for(var i=0,l=items.length;i<l;i++){

      collection.find({name:items[i].name}).toArray(function(err,itens){  
        var l;

      });

    }

});

mongodb.close();

//遍历数据

return callback(items);

});

});

});

这里在查询到collection.find({name:items[i].name}).toArray(function(err,itens){var l;}); 时,这里查询失败,断点始终进入不了var l;上

我用第二种方法有尝试,就是

mongodb.open(function(err, db){

if(err){

return callback(err);

}

//读取 users 集合

db.collection(‘question’, function(err, collection){

if(err){

mongodb.close();

return callback(err);

}

//查找用户名 name 值为 name文档

collection.find({hide:{$ne:false}}).limit(5).sort({time:-1}).toArray(function(err,items){

if(err) throw err;

mongodb.close();

//遍历数据

return callback(items);

});

});

});

这个查询完后,我先把items中的name放到一个数组,然后 再次打开mongodb.open 遍历查找

这样两种查询都无法二次查到info 表里面的内容,每次都是collection.find() 这里出错

求大神帮助


5 回复

在Node.js中使用MongoDB进行联表查询时,确实需要处理异步操作。你遇到的问题主要是由于异步操作导致的数据未准备好就被访问了。我们可以使用Promise或者async/await来更好地管理异步操作。

以下是一个改进后的示例代码,展示了如何使用async/await来实现你的需求:

const MongoClient = require('mongodb').MongoClient;
const url = 'mongodb://localhost:27017'; // 替换为你的MongoDB连接字符串

async function getQuestionWithAvatar() {
  let client;
  try {
    client = await MongoClient.connect(url, { useNewUrlParser: true, useUnifiedTopology: true });
    const db = client.db('yourDatabaseName'); // 替换为你的数据库名

    const questions = await db.collection('question').find({ hide: { $ne: false } }).limit(5).sort({ time: -1 }).toArray();
    
    const promises = questions.map(async (question) => {
      const info = await db.collection('info').findOne({ name: question.name });
      return { ...question, imgUrl: info ? info.imgUrl : null };
    });

    const result = await Promise.all(promises);
    return result;
  } catch (err) {
    console.error(err);
  } finally {
    if (client) {
      client.close();
    }
  }
}

getQuestionWithAvatar().then(result => {
  console.log(result);
}).catch(error => {
  console.error(error);
});

解释

  1. 连接数据库:使用MongoClient.connect来连接到MongoDB数据库。
  2. 查询问题集合:使用find方法查询question集合,并限制结果数量、排序。
  3. 并行查询信息:使用mapPromise.all来并行处理每个问题,查询对应的info集合。
  4. 合并结果:将查询到的信息合并到问题对象中,返回最终结果。
  5. 错误处理:使用try/catch块来捕获可能的错误。
  6. 关闭连接:确保在完成所有操作后关闭数据库连接。

这种方法利用了async/await来简化异步操作的处理,避免了回调地狱,并且能够正确地等待所有的查询完成后再返回结果。


自己解决了 异步的坑 db.collection(‘info’, function(err, collection){

    for(var i=0,l=items.length;i<l;i++){
  collection.find({name:items[i].name}).toArray(function(err,itens){ 

    var l;


  });


}

});

mongodb.close();

这个 mongodb.close();在链接info时就执行了,当具体循环时,mongodb已经关闭,所以无法查询

另外一个坑:

for(var i=0,l=items.length;i<l;i++){

collection.find({name:items[i].name}).toArray(function(err,itens){

        var l;

});

}

这个循环异步发出,var l;断点这个是谁先查到数据,谁先返回。

表设计不够好,将这两个信息放在一起 会有什么问题么

恩~第一次用mongodb,都是摸索着用,

这两个表一个是用户提问题,记录问题的表, 一个是用户注册存放用户信息的表

针对你的需求,可以在 Node.js 中使用 MongoDB 的聚合框架来实现联表查询。不过,由于 MongoDB 是文档型数据库,它不支持传统的 SQL 联表查询,但可以使用 $lookup 操作符来模拟类似的功能。

以下是一个示例代码,展示如何使用 MongoDB 的聚合框架来实现你的需求:

const MongoClient = require('mongodb').MongoClient;
const uri = 'mongodb://your_connection_string';

MongoClient.connect(uri, { useNewUrlParser: true, useUnifiedTopology: true }, (err, client) => {
    if (err) {
        console.error('Failed to connect to MongoDB:', err);
        return;
    }

    const db = client.db('your_database_name');
    
    db.collection('question')
        .aggregate([
            {
                $match: { hide: { $ne: false } }
            },
            {
                $sort: { time: -1 }
            },
            {
                $limit: 5
            },
            {
                $lookup: {
                    from: 'info',
                    localField: 'name',
                    foreignField: 'name',
                    as: 'userInfo'
                }
            },
            {
                $unwind: '$userInfo'
            },
            {
                $project: {
                    name: 1,
                    faq: 1,
                    imgUrl: '$userInfo.imgUrl'
                }
            }
        ])
        .toArray((err, result) => {
            if (err) {
                console.error('Error executing aggregation:', err);
                return;
            }

            console.log(result);
            client.close();
        });
});

解释

  1. 连接到 MongoDB:首先连接到 MongoDB 数据库。
  2. 聚合操作
    • 使用 $match 过滤 hide 字段不等于 false 的文档。
    • 使用 $sorttime 字段降序排列。
    • 使用 $limit 限制返回的结果数量。
    • 使用 $lookupquestioninfo 集合关联起来。localFieldquestion 集合中的字段名,foreignFieldinfo 集合中的字段名,as 是结果字段名称。
    • 使用 $unwind 将数组结果展开成单个文档。
    • 使用 $project 来指定输出字段,包括 name, faq 和从 info 集合获取的 imgUrl
  3. 处理结果:将查询结果打印出来,并关闭数据库连接。

这种方法避免了多次查询数据库的开销,提高了性能。

回到顶部