Query with ForEach and Subquery Node JS and MSSQL

0

I have a problem that I have not found a solution yet, I have a select in a procedure, I do a forEach in the result, inside that forEach I make another select in another procedure using the Ids as per the code below.

The problem is that at the time of bulk in mongo db for some reason the function done () is calling the bulk more than once, at some point 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 the bulk more than once so it is inserted more than once, so the result is time consuming. I need done () to be called only once and right.

    
asked by anonymous 17.05.2016 / 18:41

1 answer

0

The ideal is that you transform your query into just one, bringing all the products and already relating all the skus and images. It's much more performative than doing other queries within a loop. The records coming in duplicate you deal with in the code. I did an example function to make it easier:

// 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');
}
    
20.05.2016 / 07:31