Search code examples
node.jspromiseamazon-dynamodbbluebird

Confused with promises in a loop


I'm writing a dynamodb code that does the below.

  1. Scan a particular column and get the values and add it to an array
  2. convert the array to set and back to array to get the unique values
  3. Loop through this set values as a parameter and get the actual value.

Basically trying to create a group by in DynamoDb.

Here the 1st and 2nd step I'm able to do it. but coming to step 3 I've a loop and inside the loop the code has to be executed and my code is as below.

var AWS = require("aws-sdk");
var creds = new AWS.Credentials('akid', 'secret', 'session');

AWS.config.update({
    "accessKeyId": "myAccessId",
    "secretAccessKey": "MySecretAccessKey",
    "region": "us-east-1"
});

var dynamodb = new AWS.DynamoDB.DocumentClient();

var params = {
    TableName: "MyTable",
    FilterExpression: "#target_state = :target_state",
    ExpressionAttributeNames: {
        "#target_state": "target_state"
    },
    ExpressionAttributeValues: {
        ":target_state": "5"
    }
};
var array = [];


dynamodb.scan(params).promise().then(function (data) {
    data.Items.forEach(function (itemData) {
        array.push(itemData.ruleNo)
    });
    console.log(array);
    return array;
}).then(() => {
    console.log("Entered 2nd block " + [...new Set(array)]);
    var array2 = [...new Set(array)];

    for (index = 0; index < array2.length; ++index) {
        console.log(array2[index]);
        var params1 = {
            TableName: "ChemicalData",
            FilterExpression: "#target_state = :target_state and #ruleNo=:ruleNo",
            ExpressionAttributeNames: {
                "#target_state": "target_state",
                "#ruleNo": "ruleNo"
            },
            ExpressionAttributeValues: {
                ":target_state": "5",
                ":ruleNo": array2[index]
            }
        };


return dynamodb.scan(params1).promise().then(function (data) {
            var uw = JSON.stringify((data.Items));
            return uw;
        });
    }
}).then((data) => {
    console.log(data);
}).catch(err => {
    console.log(err)
})

when I run this program, the result that I get is only one value, and that is the first array value, I'm unable to know on how can I loop through all the array variables and then do a console.log(data). please let me know on where am I going wrong and how can I fix this.

Thanks


Solution

  • Using return inside for breaks the loop. You should gather promises from inner scan into array and use Promise.all to resolve then together

    dynamodb.scan(params).promise().then(function (data) {
        data.Items.forEach(function (itemData) {
            array.push(itemData.ruleNo)
        });
        console.log(array);
        return array;
    }).then(() => {
        console.log("Entered 2nd block " + [...new Set(array)]);
        var array2 = [...new Set(array)];
        var results = []; //results array
        for (index = 0; index < array2.length; ++index) {
            console.log(array2[index]);
            var params1 = {
                TableName: "ChemicalData",
                FilterExpression: "#target_state = :target_state and #ruleNo=:ruleNo",
                ExpressionAttributeNames: {
                    "#target_state": "target_state",
                    "#ruleNo": "ruleNo"
                },
                ExpressionAttributeValues: {
                    ":target_state": "5",
                    ":ruleNo": array2[index]
                }
            };
    
            // push results to be resolved later
            results.push(dynamodb.scan(params1).promise().then(function (data) {
                var uw = JSON.stringify((data.Items));
                return uw;
            }));
        }
        // return promise that resolves when all results resolve
        return Promise.all(results);
    })