0

I'm working with AWS DynamoDB and trying to query a table for email addresses. I want to see how many of the same emails exist in the table. But for some reason when I run the function below I get undefined.

let docClient = new AWS.DynamoDB.DocumentClient();

function checkEmail(email) {
    var params = {
        TableName: "Users",
        IndexName: "email",
        KeyConditionExpression: "email=:email",
        ExpressionAttributeValues: {
            ":email": email
        }
    }
    var emails = 0;
    docClient.query(params, function (err, data) {
        if (err) {
            return -1;
        }
        else {
            emails = data.ScannedCount;
        }
    });

    return emails;
}

I think it may have to do something with the function finishing before the table is fully queried. But I don't know how I would go about solving this (async/await?).

2 Answers 2

2

There's a race condition here: checkEmail returns earlier than docClient.query invokes its callback, since docClient.query is asynchronous, but checkEmail isn't.

What you have to do is define checkEmail to work asynchronously as well, — in this case, by using Promises and async / await syntax. As Richard Dunn suggested in the comment, AWS does provide such promise in this case, so it could be used seamlessly:

const docClient = new AWS.DynamoDB.DocumentClient();

async function checkEmail(email) {
    const params = {
        TableName: "Users",
        IndexName: "email",
        KeyConditionExpression: "email=:email",
        ExpressionAttributeValues: {
            ":email": email,
        },
    };

    try {
        const data = await docClient.query(params).promise();
        return data.ScannedCount;
    } catch (error) {
        console.error(error);
        return -1;
    }
}

Now, as the function is asynchronous now, you don't just call it, you also wait until it finishes the job — and only then acquire the result:

checkEmail(email).then((emails) => {
    // `emails` is a number
});
Sign up to request clarification or add additional context in comments.

1 Comment

The entire AWS SDK exposes promises for every callback. Just use: docClient.query(params).promise() - no need to reinvent the wheel. Also, async and await are redundant here, you can just return a promise from a function and it's the same thing.
1

The callback function runs after the function returns. Change the function to this:

let docClient = new AWS.DynamoDB.DocumentClient();

function checkEmail(email) {
    return new Promise(function(resolve, reject) {
        var params = {
            TableName: "Users",
            IndexName: "email",
            KeyConditionExpression: "email=:email",
            ExpressionAttributeValues: {
                ":email": email
            }
        }
        docClient.query(params, function (err, data) {
            if (err) {
                reject(err); //Error
            }
            else {
                resolve(data.ScannedCount); //OK
            }
        });
    });
}

You'll also need to change wherever you're calling the function from; from this:

checkEmail(someValue);

to one of these:

//Change the function you're calling the function from to an ASYNC function:
async function myFunction() {
    await checkEmail(someValue);
    //DO SOMETHING
}

or, if you can't do that:

checkEmail(someValue).then(function(returnValue) {
    //DO SOMETHING HERE
});
//NOT HERE

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.