node.js запрос mysql в цикле for

У меня два запроса.
Первый,

SELECT auctions.name, wowitemdata.itemName, auctions.itemId, 
auctions.buyout, auctions.quantity
FROM auctions
INNER JOIN wowitemdata ON auctions.itemId = wowitemdata.itemID;

возвращает такие данные:

{
name: 'somename',
itemName: 'someitemname',
itemId: '0000',
buyout: '0001',
quantity: '5',
}

Второй запрос использует данные из #1, чтобы получить count() товаров дешевле, чем itemId. Ответ должен быть добавлен к #1 как новый элемент -> 'подрезание'.

Моя функция:

function checkUndercut(data, length){
    var Select = 'SELECT COUNT(auctions.itemId) AS cnt ';
    var From = 'From `auctions` ';
    var Where = 'WHERE auctions.itemId LIKE ? AND buyout < ?';
    var sql = Select + From + Where;
    for(i = 0, len = length; i < len; i++){
        var inserts = [data[i]['itemId'], data[i]['buyout']];
        var ssql = mysql.format(sql, inserts);
        data[i]['undercut'] = i;
        connection.query(ssql, function(err, rows, fields){
            if(!err){
                console.log("check Undercut: " + rows[0].cnt);
                data[i]['undercut'] = rows[0].cnt;
            } else {
                console.log("Error while performing Query");
            };
        });
    };
}

Из-за асинхронного характера запроса я не могу использовать переменную цикла for для добавления данных.
Как это обойти?

Редактировать: Моя новая проблема:
Когда я ищу имя (searchobj), возвращаемые данные отстают на один шаг.
Допустим, я ищу Тима, но ничего не появляется.< br /> Скажем, я ищу Финна, появляются мои данные о Тиме.

Я подозреваю, что это из-за того, как я получил данные из моей функции checkUndercut.
Я создал новую переменную верхнего уровня, appdata и после использования предложения @simple_programmers я поместил свой новый код следующим образом:

function(err){
        if(err){
          //handle the error if the query throws an error
        }else{
            appdata = data;
            console.log(appdata);
          //whatever you wanna do after all the iterations are done
        }
    });

console.log отправляет правильную информацию, поэтому моя проблема связана с преждевременной отправкой ответа функцией get.

Моя функция получения:

app.get('/test',function(req, res) {
    console.log("app.get "+searchobj);
    var sqlSELECT = 'SELECT auctions.name, wowitemdata.itemName, auctions.itemId, auctions.buyout, auctions.quantity ';
    var sqlFROM = 'FROM `auctions` ';
    var sqlINNER ='INNER JOIN `wowitemdata` ON auctions.itemId = wowitemdata.itemID ';
    var sqlWHERE = 'WHERE auctions.name LIKE ?';
    var sql = sqlSELECT + sqlFROM + sqlINNER + sqlWHERE;
    var inserts = [searchobj];
    var sql = mysql.format(sql, inserts);
    //console.log("Query: "+sql);
    connection.query(sql, function(err, rows, fields) {
      if (!err){
        var rowLen = rows.length;
        checkUndercut(rows, rowLen);
        console.log(appdata);
        res.send(appdata);
                } else {
    console.log('Error while performing Query.');
    };
    
    });
}); 

Мои вопросы:

1 Каков правильный способ отправки данных из асинхронной функции?

2 Есть ли способ заставить мой app.get или res.send ждать, пока мои данные не будут получены, прежде чем отправлять их?

Редактировать 2: я могу заставить его работать, поместив весь код в мой app.get(), но должно быть более элегантное и легко читаемое решение?


person user45706    schedule 13.10.2016    source источник
comment
Какой у вас первый запрос? Я спрашиваю, потому что намного предпочтительнее свернуть их вместе в хранимую процедуру, присоединиться/выбрать, чем иметь много возвратов к базе данных (она почти наверняка может накапливать данные для вас).   -  person msanford    schedule 13.10.2016
comment
Первый запрос выглядит следующим образом: «ВЫБЕРИТЕ аукционы.имя, wowitemdata.itemName, аукционы.itemId, аукционы.выкуп, аукционы.количество ИЗ auctions ВНУТРЕННЕГО СОЕДИНЕНИЯ wowitemdata НА аукционах.itemId = wowitemdata.itemID». Редактировать: проклятое форматирование   -  person user45706    schedule 13.10.2016


Ответы (3)


На мой взгляд, лучший способ сделать это — использовать модуль узла с именем async для параллельного запуска и иметь один обратный вызов, когда все будет завершено.

Для подобных ситуаций в модуле async определено множество методов, и я бы рекомендовал forEachOf.

Учитывая, что ваш параметр data представляет собой массив, он выглядит примерно так:

function checkUndercut(data, length){
    var Select = 'SELECT COUNT(auctions.itemId) AS cnt ';
    var From = 'From `auctions` ';
    var Where = 'WHERE auctions.itemId LIKE ? AND buyout < ?';
    var sql = Select + From + Where;
    async.forEachOf(data, function (dataElement, i, inner_callback){
        var inserts = [dataElement['itemId'], dataElement['buyout']];
        var ssql = mysql.format(sql, inserts);
        dataElement['undercut'] = i;
        connection.query(ssql, function(err, rows, fields){
            if(!err){
                console.log("check Undercut: " + rows[0].cnt);
                dataElement['undercut'] = rows[0].cnt;
                inner_callback(null);
            } else {
                console.log("Error while performing Query");
                inner_callback(err);
            };
        });
    }, function(err){
        if(err){
          //handle the error if the query throws an error
        }else{
          //whatever you wanna do after all the iterations are done
        }
    });
}

Итак, что в основном делает, так это то, что он перебирает ваш массив data и выполняет запрос для каждого элемента этого массива. После выполнения запроса он вызывает метод обратного вызова, локальный для этой итерации. Как только все итерации завершены (т.е. вызывается последний локальный обратный вызов), он вызывает окончательный обратный вызов, в котором вы можете делать все, что хотите, позже, когда все ваши запросы будут выполнены.

Подробнее о forEachOf здесь — https://caolan.github.io/async/docs.html#eachOf

Асинхронный модуль — https://caolan.github.io/async/

person Simple_Programmer    schedule 13.10.2016
comment
Я новичок в асинхронной магии, поэтому, пожалуйста, потерпите меня. У меня возникли проблемы с тем, чтобы моя функция app.get отправляла данные в правильном порядке, с (вероятно, окольным путем), как я это исправил, мои поиски отстают на один шаг. Скажем, я ищу Тима, ничего не появляется. Скажем, я ищу Финна следующим, появляются мои данные о Тиме. Я редактирую свой исходный пост, чтобы отразить эти новые вопросы. - person user45706; 13.10.2016

попробуй это

const connection = mysql.createConnection({
  host: 'localhost',
  user: 'root',
  password: 'pass',
  database: 'db'
});

connection.connect(function(err) 
{
  if (err) throw err;
    connection.query("SELECT * FROM tb", function (err, result, fields) 
    {
      if (err) throw err;
      var test = result;
      var length = Object.keys(result).length;
      console.log(   length   );

      for (var i = 0; i < length; i++) 
      {

      console.log(result[i].column_name);

      };

    });

});
person Ryosuke Hujisawa    schedule 07.06.2018

Если вас просто беспокоит область действия i для получения значения по определенному индексу, просто используйте array.forEach.

data.forEach(function(datum, i){
  var inserts = [datum['itemId'], datum['buyout']];
  var ssql = mysql.format(sql, inserts);
  datum['undercut'] = i;
  connection.query(ssql, function(err, rows, fields){
    ...
    datum['undercut'] = rows[0].cnt;
    ...
  });
  ...
});
person Joseph    schedule 13.10.2016