请教for循环中查询数据库时,只能得到最后一次查询结果?
发布于 2年前 作者 hnliji1107 1873 次浏览

我express框架做blog的过程中遇到个很纠结的问题,我的mongo数据库里有两张表,

一个是存储用户信息的user表,字段是_id,email,name,password等…

一个是存储文章的blog表,字段是_id,title,content,author_id等…

blog表里的每篇文章除了标题内容等之外还有个命名为author_id的字段,存储文章作者id。

我现在想循环blog表,读取所有文章,找到每篇文章的author_id,

然后根据该author_id读取user表里的name字段,该字段表示作者名称。

但是在循环过程中发现读不到每个for循环时的序列值,只能拿到最后for结束后的序列值。

这是因为数据库查询是异步的,采用回调的方式处理。

这种情况下,我怎么拿到每次for循环的值呢?下面是代码:

module.exports = function(req, res) { var blog = require(‘…/models/blog’); var user = require(‘…/models/user’); var session_user = req.session.user; var condition = session_user? {author_id: session_user._id} : null;

blog.get(null, function(status, message) {
    for (var i=0, count=message.length; i<count; i++) {
        var label_arr = message[i].label.split(',');
        var j = 0;
        var num = label_arr.length;
        var new_arr = [];

        for (; j<num; j++) {
            var k = 0;
            var label_arr2 = label_arr[j].split(',');
            var len = label_arr2.length;

            for (; k<len; k++) {
                var clean_elem = label_arr2[k].replace(/(^[ \t\n\r]+)|([ \t\n\r]+$)/g,'');

                if (clean_elem != '') {
                    new_arr.push(clean_elem);
                }
            }
        }

        message[i].label = new_arr;

        user.get({_id: message[i].author_id}, function(status, user_message) {
    //这个回调函数只能被调用一次,根本拿不到对应用户的name值,我咧个去,纠结死了。。。
    message[i].author_name = user_message[0].name; //这里出错,i的值永远是count

            blog.get(condition, function(status, self_message) {
                res.render('index', {
                    title: 'NodeJs学习站',
                    type: 'index',
                    loginer: session_user,
                    blog: message,
                    self_blog: self_message
                });
            });
        });
    }
});

};

12 回复

你这个javascript绑定的变量发生变化的问题 用下面这种方式解决,一定要用下面这个方式绑定一下变量。

function (i){ do(i); }(i变量绑定)

多看看javascript基础吧,js的坑还是很多的,除了这个,比较有名的还有this关键字,建议看看javascript高级程序设计。

你这种方法,我已经试过了,是不行的。

这个是典型的用同步的思路去写异步的程序,楼上的闭包可以解决问题,但是看上去比较怪异,难以理解。 最简单的用list的forEach来实现。 message.forEach(function(msg){ … … … user.get({_id: msg.author_id}, function(status, user_message) {}) … … … })

是的,这是更好的方式

你这种闭包写法也要分场合的,不是什么地方都能用啊

谢谢,我试下forEach。

我试了下,最后得到的还是只有一个结果,forEach跟for循环是一样的,附上user.get方法:

//查询用户信息 User.get = function(condition, callback) { if (condition && condition._id) { condition._id = new ObjectID(condition._id); }

User.base(function(collection) {
    collection.find(condition).toArray(function(err, user) {
        if (err) {
            return callback(0, err);
        }

        return callback(1, user);
    });
});

};

这代码看的好累,你在异步循环里面调用 res.render?

是的,因为res.reder需要异步请求的数据。

@hnliji1107 res.reder只能调用一次吧

@hnliji1107 res.render不能调用多次的。如果想把多次调用de结果输出到前端,可以在外面放一个数组变量,然后在每次de循环调用取数据的时候push结果到外面的数组,最后再render。

回到顶部