Query with Foreach and Subquery Node JS and MSSQL

Asked

Viewed 322 times

0

I have a problem that I have not found solution yet, I have a select in a Precedent, I do a foreach in the result, inside this foreach I do another select in another Precedent using the Ids as code below.

The problem is that when it comes to making Bulk in Mongo db for some reason Function done() is calling Bulk more than once, at some point the done() is being called more than once.

var consultaSQL = function(){

  console.time('sql');
  sequelize.query('PRS_MONGO_PRODUTO;', { type: sequelize.QueryTypes.SELECT }).then(function(result){
    console.log(result.length);
    console.timeEnd('sql');

    done = _.after(result.length, function () {
      if(result.length > 0) {
        var i = 1;
        var bulk = Detalhe.collection.initializeOrderedBulkOp();
        console.time('bulk');
        result.forEach(function(p){
          bulk.find({ produtoId: p.produtoId, clienteId: p.clienteId }).upsert().replaceOne(p);
        });
        console.timeEnd('bulk');

        console.log('Quantidade Exec: ' + result.length);
        console.time('exec');

        bulk.execute(function (err, result) {
          if(err) console.error(err);
          console.timeEnd('exec');
          console.log('##################### Inicia em 5 Segundos! #####################');
          var teste =  setTimeout(function () {
            consultaSQL();
          }, 5000);
        });
      }
      else {
        console.log('##################### Sem registros! #####################');
        setTimeout(function () {
          consultaSQL();
        }, 30000);
      }
    });
    if(result.length == 0) done();
    result.forEach(function(p){
      p.skus = [];
      sequelize.query('PRS_PESQ_PRODUTO_INDEXACAO_MONGO ' + p.clienteId + ', ' + p.produtoId, { type: sequelize.QueryTypes.SELECT }).then(function(resultA){
        done2 = _.after(resultA.length, function () {
          done();
        });

        if(resultA.length == 0) done2();

        resultA.forEach(function(s){
          sequelize.query('select caminho as imagem from produtoSkuImagem where produtoSkuId = ' + s.produtoSkuId, { type: sequelize.QueryTypes.SELECT }).then(function(resultB){

            done3 = _.after(resultB.length, function () {
              done2();
            });
            s.imagens = [];
            s.imagens.push(resultB)
            p.skus.push(s);
            done3();
          });

        });

      });
    });
  }).catch(function(err){
    console.error(err);
    process.exit();
  });
}

The result he has to generate is this below:

{
"_id" : ObjectId("573b202f6d16e35c707c3119"),
"clienteId" : 1,
"produtoId" : 3948,
"parceiroId" : 1,
"codigoProduto" : "2014526",
"nome" : "Armário Blumenau Branco - Politorno",
"descricao" : "Armário para Forno Microondas, com duas portas.Fabricado em chapas de 15mm. Limpeza do móvel deve ser feita com um pano umedecido com água.",
"codigoMarca" : 3150,
"marca" : "Politorno",
"produtoSkuId" : 4424,
"peso" : 23250,
"altura" : 11,
"comprimento" : 109,
"estoque" : 1,
"preco" : 185.31,
"precoDe" : 285,
"pontos" : 195,
"parcelamento" : 1,
"imagem" : "https://static.wmobjects.com.br/imgres/arquivos/ids/2509026",
"ativo" : 1,
"dataCadastro" : ISODate("2016-03-21T11:10:53.620Z"),
"dataAtualizacao" : ISODate("2016-05-17T10:29:27.590Z"),
"skus" : [ 
    {
        "clienteId" : 1,
        "produtoId" : 3948,
        "parceiroId" : 1,
        "codigoProduto" : "2014526",
        "nome" : "Armário Blumenau Branco - Politorno",
        "descricao" : "Armário para Forno Microondas, com duas portas.Fabricado em chapas de 15mm. Limpeza do móvel deve ser feita com um pano umedecido com água.",
        "codigoMarca" : 3150,
        "marca" : "Politorno",
        "produtoSkuId" : 4424,
        "peso" : 23250,
        "altura" : 11,
        "comprimento" : 109,
        "estoque" : 1,
        "preco" : 185.31,
        "precoDe" : 285,
        "pontos" : 195,
        "parcelamento" : 1,
        "imagem" : "https://static.wmobjects.com.br/imgres/arquivos/ids/2509026",
        "ativo" : 1,
        "dataCadastro" : ISODate("2016-03-21T11:10:53.620Z"),
        "dataAtualizacao" : ISODate("2016-05-17T10:29:27.590Z"),
        "imagens" : [ 
            [ 
                {
                    "imagem" : "https://static.wmobjects.com.br/imgres/arquivos/ids/2514797"
                }, 
                {
                    "imagem" : "https://static.wmobjects.com.br/imgres/arquivos/ids/2514804"
                }, 
                {
                    "imagem" : "https://static.wmobjects.com.br/imgres/arquivos/ids/2514811"
                }
            ]
        ]
    }
]

}

This code works the problem is that it calls Bulk more than once so it enters more than once, so the result is time consuming. I need the done() to be called only once and in the right way.

1 answer

0


The ideal is that you turn your query into just one, bringing all the products and relating already with all the skus and images. It’s much more performative than doing other queries within a loop. The records coming duplicated you treat it in the code. I made an example function to facilitate:

// Esse é o resultado da sua query com todos os joins
var resultset = [
	{prod: 1, prod_nome: 'prod_1', sku: 51, sku_nome: 'a', img: '1.jpg'},
	{prod: 1, prod_nome: 'prod_1', sku: 51, sku_nome: 'a', img: '2.jpg'},
	{prod: 1, prod_nome: 'prod_1', sku: 51, sku_nome: 'a', img: '3.jpg'},
	{prod: 1, prod_nome: 'prod_1', sku: 52, sku_nome: 'b', img: '1.gif'},
	{prod: 1, prod_nome: 'prod_1', sku: 52, sku_nome: 'b', img: '2.gif'},
	{prod: 1, prod_nome: 'prod_1', sku: 52, sku_nome: 'b', img: '3.gif'},
	{prod: 2, prod_nome: 'prod_2', sku: 53, sku_nome: 'c', img: 'c1.jpg'},
	{prod: 2, prod_nome: 'prod_2', sku: 53, sku_nome: 'c', img: 'c2.jpg'},
	{prod: 2, prod_nome: 'prod_2', sku: 54, sku_nome: 'd', img: 'd.jpg'}
];

function Resultset(rs){
	var o = this;
	o.reader = rs;
	o.idx = -1;
	o.len = rs.length;
	o.current = null;
	o.fieldKeys = {}
	o.lastFKeyIteration = null;
	o.end = false;
}
Resultset.prototype.get = function(field) {
	return this.current[field];    
}
Resultset.prototype.next = function(fieldKey) {
	var o = this;
	var rs = o.reader;
	fieldKey = fieldKey || null;
	var nextFK = fieldKey != o.lastFKeyIteration && o.lastFKeyIteration != null;
	if(!nextFK)
		o.idx++;
				
	o.lastFKeyIteration = fieldKey;
	if(fieldKey != null && typeof o.fieldKeys[fieldKey] == 'undefined')
	   o.fieldKeys[fieldKey] = null;
	   
	if(!o.end){
		if((fieldKey != null && nextFK) || o.idx < o.len) {
			if(fieldKey != null) {
				for(var fk in o.fieldKeys) {
					var _v = rs[o.idx][fk];
					if(_v != o.fieldKeys[fk] && fk != fieldKey)
						return false;

					if(fk == fieldKey) {
						o.fieldKeys[fieldKey] = _v;
						break;
					}
				}
			}
			
			o.current = rs[o.idx];
			return true;
		}
		o.end = true;
		return false;
	}
	return false;
}




// Para utilizar ficaria algo do tipo:
var rs = new Resultset(resultset);

var data = [];
if(rs.next('prod')){
  do{
    var prod = {
      id: rs.get('prod'),
      nome: rs.get('prod_nome'),
    };
    var skus = []; 
    while(rs.next('sku')){
      var sku = {
        id: rs.get('sku'),
        nome: rs.get('sku_nome')
      };
      var imgs = [];
      while(rs.next('img')){
        imgs.push(
          rs.get('img')
        );
      }
      sku.imagens = imgs;
      skus.push(sku);
    }
    prod.skus = skus;
    data.push(prod);
  }
  while(rs.next('prod'));

  console.log(data);
}
else{
  console.log('Nenhum registro');
}

  • Thank you very much, it worked perfectly, now I will implement some more fields I have and already was. TKS!

Browser other questions tagged

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