#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.