Dylan Cross
Dylan Cross

Reputation: 5986

Node.Js API wait for dynamodb calls to finish to send to browser

I have a complex amount of code for dynamodb calls to the database. Basically I have several database calls to linked at the end of each other, and then on top of that I need to loop through multiple items. Then at the end I need to be able to send a new JSON object to the front-end to display properly. The problem is that the Map finishes before the Database calls finish, so the "newItems" variable is undefined. Basically I need the map to wait for the database to finish before going to the next iteration.

The code snippet is not the complete call, but it's the relevant area. This is all wrapped in an app.get() as well.

        const newItems = items.map(function(item, i) {
          dynamoDb.scan({
            TableName: GIVEAWAY_ENTRIES_TABLE,
            FilterExpression: "giveawayId = :giveawayId",
            ExpressionAttributeValues: {
              ":giveawayId": item.id
            }
          }, (error, ge_result) => {
            dynamoDb.scan({
              TableName: USERS_TABLE,
              FilterExpression: "sessionId = :sii",
              ExpressionAttributeValues: {
                ":sii": sessionId
              }
            }, (error, result) => {
              dynamoDb.scan({
                TableName: GIVEAWAY_ENTRIES_TABLE,
                FilterExpression: "giveawayId = :giveawayId and userId = :userId",
                ExpressionAttributeValues: {
                  ":giveawayId": item.id,
                  ":userId": result.Items[0].id
                }
              }, (error, gemc_result) => {

                console.log("RESPONSEEEEEEE");
                return {
                  id: item.id,
                  title: item.title,
                  thumbnail: item.thumbnail,
                  photo: item.photo,
                  description: item.description,
                  myCount: gemc_result.Count,
                  totalCount: ge_result.Count
                }
              });
            });
          })

          console.log("END OF MAPPPPP");

        });

        console.log("#######", newItems);
        res.json({'success': true, data: newItems});

Upvotes: 0

Views: 1617

Answers (1)

dpolicastro
dpolicastro

Reputation: 1519

First thing I recommend you is to use the native function promisify to make AWS sdk functions returns a promise. It's way more readable! Then you can take advantage of node.js promises to handle async code, you can use it like that:

const util = require('util');
const safePromisify = function (fun, methodsArray) {
  const suffix = 'Async';
    methodsArray.forEach(method => {
      fun[method + suffix] = util.promisify(fun[method]);
  });
}
safePromisify(dynamoDb, ['scan']);

const newItems = items.map(function async(item, i) {
//                                  ^^^^^ this is required to use await

// Note the async and await keywords
  let ge_result = await dynamoDb.scanAsync({
    TableName: GIVEAWAY_ENTRIES_TABLE,
    FilterExpression: "giveawayId = :giveawayId",
    ExpressionAttributeValues: {
      ":giveawayId": item.id
    }
  });

  let result = await dynamoDb.scanAsync({
    TableName: USERS_TABLE,
    FilterExpression: "sessionId = :sii",
    ExpressionAttributeValues: {
      ":sii": sessionId
    }
  });

  let gemc_result = await dynamoDb.scanAsync({
    TableName: GIVEAWAY_ENTRIES_TABLE,
    FilterExpression: "giveawayId = :giveawayId and userId = :userId",
    ExpressionAttributeValues: {
      ":giveawayId": item.id,
      ":userId": result.Items[0].id
    }
  });

  return {
    id: item.id,
    title: item.title,
    thumbnail: item.thumbnail,
    photo: item.photo,
    description: item.description,
    myCount: gemc_result.Count,
    totalCount: ge_result.Count
  }
});

Note: You have to append the word Async on the function call

Upvotes: 3

Related Questions