Узел Mysql асинхронные множественные запросы

#mysql #node.js

#mysql #node.js

Вопрос:

Мне было интересно, какой лучший способ обработки вложенных mysql-запросов — это nodejs.

Итак, что-то вроде этого:

 connection.query("SELECT * FROM blogs ORDER BY time DESC", function(err, blogs, fields) {

   for (blog in blogs) {

        connection.query("SELECT * FROM tags WHERE blog_id='blog.id' ", function(err, tags, fields) {

        blog.tags = tags

     });

   }

   res.send(blogs)

});
  

Это, очевидно, не работает из-за асинхронного характера. Результат уже возвращается до извлечения тегов.

Я читал об узле, обратных вызовах и обещаниях, похоже, это правильный путь. Но я не могу понять, как мне лучше всего использовать их в этом небольшом примере.

Спасибо!

Комментарии:

1. Это было бы хорошей возможностью начать использовать библиотеку обещаний, такую как Q , в данном случае это Q.spread метод (или, может быть, эти примеры сокращения

Ответ №1:

Поэтому вам нужно дождаться возврата всех обратных вызовов, прежде чем отправлять ответ. Если мы игнорируем обработку ошибок и пустые результаты для простоты, это можно сделать аналогично:

 var callback = function(blogs) {
    res.send(blogs);
}

connection.query("SELECT * FROM blogs ORDER BY time DESC", function(err, blogs, fields) {
    var pending = blogs.length;

   for (blog in blogs) {

        connection.query("SELECT * FROM tags WHERE blog_id='blog.id' ", function(err, tags, fields) {
        blog.tags = tags;

        if (0 === --pending) {
            callback(blogs);
        }
     });
   }
});
  

Что касается promises, загляните в функцию Promise.all, которая возвращает новое обещание. Эти обещания разрешаются, когда разрешаются все обещания, переданные ему в массиве. С библиотекой Q это должно быть что-то вроде:

 var getTags = function(blog) {
    var deferred = Q.defer();
    connection.query("SELECT * FROM tags WHERE blog_id='blog.id' ", function(err, tags, fields) {
        blog.tags = tags;
        deferred.resolve();
    });
    return deferred.promise;
}

var promises = blogs.map(getTags(blog));

Q.all(promises).then(res.send(blogs));
  

Ответ №2:

Вы можете использовать модуль async.series (для перебора запросов `)

 async.eachSeries(blogs,
                function (query, callback) {

                    connection.query(blogs.blog, "SELECT * FROM tags WHERE blog_id='blog.id'" , function (err, result) {
                        if (err) {

                            //throw err;
                            callback(err, null);
                            return;

                        } else {
                            console.log('Query executed successfully');
                            blogs.blog.tags = tags;
                        }
                        callback(null, blogs.blog);

                    });

                },

                function finalCallback(err, results) {

                            return callback(null, results);
                        });
                    }
                });

        });



    });`
  

Вы можете улучшить это с помощью функции and query.on (для обработки каждой строки)

Ответ №3:

Вы можете попробовать что-то вроде этого;

 connection.query("SELECT * FROM blogs ORDER BY time DESC", fetchedBlogs);

function fetchedBlogs(err, blogs, fields) {

    if (err || !blogs || !blogs.length) {
        // an error occurred or no blogs available
        // handle error or send empty blog array
        return res.send();
    }

    var count = blogs.length;

    (function iterate(i) {
            if (i === count) {
                // all blogs processed!
                return res.send(blogs);
            }

            var blog = blogs[i];

            connection.query("SELECT * FROM tags WHERE blog_id='"   blog.id  
                "'", fetchedTags);

            function fetchedTags(err, tags, fields) {
                blog.tags = tags;
                iterate(i 1);
            });
    })(0);
}
  

Надеюсь, это поможет.

Комментарии:

1. Почему этот ответ отклонен? Я согласен, что идеальным решением этой проблемы было бы получение обоих данных в одном запросе. Это решение работает, если необходимы два запроса, этот фрагмент также предоставляет простой способ обработки обратных вызовов в цикле без использования библиотеки управления потоком, такой как async / promise / etc.