Mysql query with subquery in Nodejs

Asked

Viewed 734 times

3

I have the following structure in the following tables.

partner (idParceiro, name, email, phone) example partnerTag (idPartner, tag)

What I need to do, a select in the partner table and do a for in the result and query the partner table by idParty and bring the results to fill in a Json that stays that way.

[{
  nome: 'nome teste',
  email: 'email teste',
  telefone: 1199999999,
  tags: ['tag1', 'tag2', 'tag3']
}, {
  nome: 'nome teste',
  email: 'email teste',
  telefone: 1199999999,
  tags: ['tag1', 'tag2', 'tag3']
}]

The problem is that when I consult the first table and do a go in the result to get the ID and go in the other table it gets lost by being async.

How can I resolve this in NODE.JS because I have several queries that depend on another to generate a Json.

Follow my code below.

router.route('/parceiro').get(function(req, res) {
  parceiro.consultar(req, function(err, rows){
    if(err) return res.status(400).json(err);

    var p  = [];
    _.each(rows, function(one) {
      var pa = {};
      pa.parceiroId = one.parceiroId;
      pa.clienteId = one.clienteId;
      pa.nome = one.nome;
      pa.imagemDestaque = one.imagemDestaque;
      pa.imagemLogo = one.imagemLogo;
      pa.desconto = one.desconto;
      pa.titulo = one.titulo;
      pa.descricao = one.descricao;
      pa.urlSite = one.urlSite;
      pa.validadeDe = one.validadeDe;
      pa.validadeAte = one.validadeAte;
      pa.isCupom = one.isCupom;
      pa.urlOferta = one.urlOferta;
      pa.cupomDesconto = one.cupomDesconto;
      pa.ativo = one.ativo;
      pa.dataCadastro = one.dataCadastro;
      pa.tags = [];
      parceiro.tag(req, function(err, r){
        _.each(r, function(two) {
          pa.tags.push(two.tag);
        });
      });
      pa.categorias = [];
      pa.regioes = [];
      p.push(pa);
    });
    return res.status(200).json(p);
  });
});

  • Please put the code in text and not image. The logic of res.status must be inside parceiro.tag(), and then wait for that answer/callback. But you couldn’t do it in one SELECT with a JOIN?

  • Not in a single select because I have a partner can have 100 tags and categories and regions although they will be in the formed {idRegiao:1, name:'region name'}.

  • Wouldn’t it be cleaner var pa = one;? instead of passing the properties one by one?

  • one is from the partner table that does not have the tags properties, categories and regions, only if they can be included later.

  • Okay, and you want the same for the regions, and categories like parceiro.tag?

  • Yes I have that for and inside I want to consult the 3 tables separately, the problem is only that when it enters the partner method.tag() the value is inside and I can’t play for the pa.tags.push().

  • I understand the problem and see the mistake. I ask to better hit the answer.

  • The table is called tag or tags? you have the property as tags but the table tag? and the others?

  • I left an answer, this is bedtime. I’ll take a look tomorrow to see if you understood the logic and if it helped you. (Or if you found a bug :P )

Show 4 more comments

3 answers

1

Another approach, even better than doing this in Node.js is to make this data merge in Mysql.

So you can concatenate the tags with the GROUP_CONCAT and receive this in the columns of row that Mysql returns, without having to make several queries to fetch "pieces" of information.

Forehead like this:

SELECT p.id, p.nome, GROUP_CONCAT(t.tag) AS tags FROM parceiro AS p
INNER JOIN parceiroTag AS t ON p.id = t.parceiroid
GROUP BY id

Example here (link).

0

You need to string that logic together just to call res.status().json() when that object has all the properties you need. And as everything is asynchronous the thing complicates a little.

A good library to work these threads, is called async. But doing "by hand" I think you need something like this:

function waitForIt(obj, tables, done) {
    var callbacks = 0;
    return function(err) {
        if (err) return console.log(err);
        callbacks++;
        if (callbacks == tables.length) done(err, obj);
    }
}

function join(table, obj, cb) {
    parceiro[table](req, function(err, r) {
        obj[table] = r.map(function(row) {
            return row.tag;
        });
        cb(err);
    });
}

router.route('/parceiro').get(function(req, res) {
    parceiro.consultar(req, function(err, rows) {
        if (err) return res.status(400).json(err);
        rows.forEach(function(pa) {
            var cb = waitForIt(pa, ['tag', 'regi'], function(err, obj) {
                if (err) return res.status(400).json(err);
                return res.status(200).json(obj);
            });
            tables.forEach(function(table) {
                join(table, pa, cb);
            });
        });
    });
});

The idea is to call all the tables you need, add to the object what the table brings and then, only when all the callbacks of the Subqueries have been called; only then call the last callback I named done.

Notes:

  • #1 I’ve made the code now, I haven’t tested it, but it’s the logic you need.
  • #2 still think you could do this only with Mysql :)
  • #3 use if (err) return res.status(400).json(err); will expose internal application errors to the user and may cause gaps in BD security.

0

I was able to do it this way.

exports.consultar  = function (req, callback) {
  req.getConnection(function(err,connection){
    connection.query('SELECT * FROM parceiro', function(err, result){
      done = _.after(result.length, function () {
        callback(err, result)
      });
      result.forEach(function(pa){
        connection.query('SELECT * FROM parceiroTag where parceiroId = ' + pa.parceiroId, function(err, result){
          pa.tags = [];
          for (var i = 0; i < result.length; i++) {
            pa.tags.push(result[i].tag);
          }
          done();
        });
      });
    });
  });
};

Thanks for all your help.

  • 1

    You must choose a correct answer.

  • This answer uses the same logic I suggested, via _.after underscore. I will join a response with Mysql only

Browser other questions tagged

You are not signed in. Login or sign up in order to post.