0

I am using mongodb with mongoose.

I have the some collections with the next models:

a. Model: Product

b. Model: Details

I need return a dataset with the total items in Product, and to each product item, i need calculate the quantity by loop your details in Model Details.

My problem is how do I could set the quantity in my data array, after execute the "promise_3". I´d need to know the index of the data array to do it, but How could I do it?

The result will be something as:

response:{
total:1012, 
data:[
{id:'1',name:'xx', quantity:10},
{id:'2',name:'yy', quantity:110},
{id:'3',name:'zz', quantity:130},
...
]}

//my code with the promises

var response={};
var promise_1=Product.count({}).lean().exec();

var prommise_2=function (data){
       return Product.find(conditions)
        .limit(pageSize)
        .skip(pageSize*(pageNumber-1))
        .sort(oorder)
        .lean()
        .exec();
   }


var prommise_3= function (item){
        return Details.aggregate(
                    [
                            { "$match": { 
                                cod_material: item._id
                            }},
                            {$lookup:
                              {
                                from: "estoqueMov", //use the name of database collection not mongoose model
                                localField: "cod_mov",
                                foreignField: "_id",
                                as: "mov_doc"
                              }
                            },

                            { $unwind: "$mov_doc" },
                            {$lookup:
                              {
                                from: "Details", //use the name of database collection not mongoose model
                                localField: "mov_doc.cod_tipo_mov",
                                foreignField: "_id",
                                as: "tipo_mov_doc"
                              }
                            },

                            { $unwind: "$tipo_mov_doc"},
                            { "$group": {
                                _id: "$cod_material",
                                total: { "$sum": 
                                        {"$multiply": 
                                         ["$quantidade",{"$cond":[
                                         {"$eq":["$tipo_mov_doc.tipo","Entrada"]} , 1,-1]}] 
                                        }
                                        } 
                            }}

                    ]);
    }

    //promise_1 is done
    promise_1.then( function(count){
         response.total=count;
         return promise_2() 
    })
    .then( function (data){
        response.data=data;
        for (var i = 0; i < response.data.length; i++) { 
          var item=response.data[i];
          //??item.quantity=0;
          return promise_3(item) 
        }
    })
    .then( function (results){
        var total=results.length>0?results[0].total:0;
        //Here is my problem How could I set the response.data index array??
        response.data[??????].quantity=total;
        callback(null,response,res);

    });
Luiz Alves
  • 2,575
  • 4
  • 34
  • 75
  • In the second callback, you `return` from the middle of your `for` loop. I don't think that's what you want. – Bergi Jul 27 '17 at 02:04
  • @ Bergi, I need calculate the quantity to each product item using promise_3. My intent was create a loop and call promise_3. Do you could suggest something different? – Luiz Alves Jul 27 '17 at 02:20
  • Well either you generate an array of `promise_3` promises, use `Promise.all`, and then iterate the `results` in pretty much the same way (the order is preserved, so you can easily use the indices into the data array). Or you put those `.then()` calls inside the loop, so that every `promise_3` has its own callback (which then can use the index by closure [provided that the loop scope is correct](https://stackoverflow.com/questions/750486/javascript-closure-inside-loops-simple-practical-example)). In any case, drop or move that `return`. – Bergi Jul 27 '17 at 02:27

1 Answers1

2

For this snippet, you should utlize Promise.all Since what you're trying to do is actually resolve 1 promise for each item inside your the array.

.then( function (data){
        response.data=data;
        for (var i = 0; i < response.data.length; i++) { 
          var item=response.data[i];
          //??item.quantity=0;
          return promise_3(item) 
        }
    })

It will look something like this

 .then( function (data){
            var promises = [];
            response.data=data;
            for (var i = 0; i < response.data.length; i++) { 
              var item=response.data[i];
              //??item.quantity=0;
              promises.push(promise_3(item)); 
            }
            return Promise.all(promises);
        })

Now essentially your next .then will not run until all promises in the promises array have been resolved.

NOTE: Order of the resulting promise.all array does maintain it's element order after completely resolving.

Given that the last .then will now be getting an array of data you will want to wrap its functionality inside a loop-- something like this (not 100% sure if this is what you want it to do, but you should get the idea.):

 for (var i = 0; i < results.length; i++) { 
          var total=results[i].length>0?results[i].total:0;
          response.data[i].quantity=total; 
 } 
88jayto
  • 659
  • 1
  • 5
  • 20
  • Thank you. It solves a part of the problem. Any suggestion to the last "then" in: response.data[??????].quantity=total; – Luiz Alves Jul 27 '17 at 02:37
  • @LuizAlves "chain it again". The answer here does `return Promise.all()` so it returns as a `Promise`, which means you just continue the chain using `.then()`. That's the point. It actually even says *"Now essentially your next `.then()` will not run until all promises in the promises array have been resolved."* – Neil Lunn Jul 27 '17 at 02:43
  • @ Neil Lunn OK, I already have a chain in the last step. My problem is that I need to set response.data[index].quantity=total and I don't have this "index" from return of Promisse.All – Luiz Alves Jul 27 '17 at 02:53
  • @88jayto Hi, Is the index of "results" the same of "response.data"? I think it can be different because promise.all runs all promises in parallel and there is no guaranty about order in the results. Am I correct? – Luiz Alves Jul 27 '17 at 02:59
  • @LuizAlves There is a guarantee of the order of the elements within the array. https://stackoverflow.com/questions/28066429/promise-all-order-of-resolved-values You may be thinking of the order in which the promises resolve, which is not guaranteed, but that's unrelated and shouldn't cause any problems. – 88jayto Jul 27 '17 at 03:07
  • Thank you very much Mr 88jayto. I will try with the code now. – Luiz Alves Jul 27 '17 at 03:20