2

I am using the following code querying a dynamodb instance from within a node.js/express framework. The code is querying a table called User which has a hash key primary key of username with no range. It has no local secondary indexes, and 3 global secondary indexes (last_name-first_name, email_last-name, and company_[no range]).

I want to prevent duplicate usernames and duplicate email addresses. I can successfully prevent duplicate usernames but not duplicate email addresses. The docs state the "ComparisonOperator": "NULL" or Exists: false lines should do it (they are mutually exclusive and I do NOT try them at same time). But, only the username validation is 'honored' by the AWS sdk, ie. the code below prevents duplicate usernames from being entered in to the system but duplicate email still occurs.

If I leave both "Expected:" keys out (username and email) the putitem simply adds a new record or updates the existing record with the same username (as documentation states and as I expect) but leaving both in, or just the email key in will NOT prevent duplicate emails in the database. Please help.

thanks

var d = new Date();
var dt = d.getTime();

params = {
    TableName: 'User',
    Expected: {
        "username": {
            Exists: false
            // tried this also ->  "ComparisonOperator": "NULL"
        },
        "email": {
            Exists: false
           // tried this also ->  "ComparisonOperator": "NULL"
        }

    },  
    Item: { 
        username: {S: req.body.username},
        created: {N: "" + dt + ""},
        company: {S: req.body.company},
        fname: {S: req.body.fname},
        lname: {S: req.body.lname},
        companies: {SS: [req.body.company]},
        email: {S: req.body.email},
        is_admin: {S: req.body.is_admin},
        is_vendor: {S: req.body.is_vendor},
        password: {S: req.body.pass}
    }
};

dynamodb.putItem(params, function(err, data) {
    var obj = new Object();
    obj.data = {};
    obj.data.username = req.body.username;
    obj.data.fname = req.body.fname;
    obj.data.lname = req.body.lname;
    obj.data.company = req.body.company;
    obj.data.email = req.body.email;
    obj.data.is_admin = req.body.is_admin;
    obj.data.is_vendor = req.body.is_vendor;
    if (err) {
        obj.status = "false";
        obj.error = err;
    }
    else{
        obj.status = "true";
    }
    res.send(JSON.stringify(obj));  
});
1

1 Answer 1

3

I recommend first doing a query against the email index to check for existence of the email address before creating the new user.

It sounds like you are expecting the update condition to act as a global unique key constraint, similar to what a relational database might offer. DynamoDB only really enforces uniqueness on the primary key attributes. The update condition is only evaluated against the item attributes that are matched by the key. Your conditional update strategy works for username, since username is the primary hash key and a duplicate username would match the same row. The condition on email only guarantees that the email field is null on the one row that matches the username key.

Sign up to request clarification or add additional context in comments.

4 Comments

thanks James, the docs don't read as clear as your explanation. Your solution of pre-checking the system for the specified email makes sense but I wanted to make sure I wasn't missing something first. Thank you sir!
UPDATE-James' suggestion to check for the email manually is the best solution but make sure you do a query (not a scan which is 'eventually consistent') and the query cant use a GLOBAL Secondary index which is 'eventually consistent' also, you have to do a query using a LSI, PK or just a query w/query filter & make sure to use a 'strongly consistent' query or you could get bad results (the second unique field [email in this case] might appear to not exist in the database but really does because of stale data returning in an eventually consistent type query).
UPDATE- you cant do a strongly consistent query on a non-indexed field per AWS docs. You cant do a strongly consistent read on a global secondary index, and you have to know the hash to do a query on a local secondary index. So, I guess you just can't have 2 unique fields independent of each other in dynamodb.
I had a similar question and posted it to the DynamoDB dev forums. You might find it helpful: forums.aws.amazon.com/thread.jspa?threadID=153653

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.