clarkie / dynogels

DynamoDB data mapper for node.js. Originally forked from https://github.com/ryanfitz/vogels
Other
490 stars 110 forks source link

Create if not exists #32

Closed rafoli closed 7 years ago

rafoli commented 8 years ago

Sorry, I just found that project. This question was already posted in the vogels's repository. But I'm duplicating it here since this project is most updated.

Hi,

I have a simple table:

const Query = vogels.define('Query', {
    hashKey: 'queryId',

    schema: {
        queryId: vogels.types.uuid(),
        name: Joi.string().required()
    },

    tableName: 'query'
});

How to avoid duplicated queries that contain the same 'name'?

I've tried the following code:

function saveQuery(query, cb) {
    var params = {};
    params.ConditionExpression = '#n <> :x';
    params.ExpressionAttributeNames = { '#n': 'name' };
    params.ExpressionAttributeValues = { ':x': query.name };

    queryModel.Query.create(query, params, function(err, res) {
        if (err) {
            console.log(err);
            cb(err);
        } else {
            cb(null, res);
        }
    });
}

But, duplicated queries have been created. Is there a way to do it using 'create'?

Thanks

clarkie commented 7 years ago

@rafoli I've been doing some digging into this and following your discussion with @set-killer on https://github.com/ryanfitz/vogels/issues/189 I think I have an answer for you.

The conditions are checked but only when the id matches an existing id. For dynamo to check for the existence of a value in a property other than a hashkey then it would need to scan the table. This is not what dynamodb is designed for.

I've just added the following example to the repo: https://github.com/clarkie/dynogels/blob/master/examples/conditionalWrites.js

clarkie commented 7 years ago

I think the documentation / api for dynogels is slightly misleading. In the dynamodb docs it states

To write an item, you use operations such as PutItem, UpdateItem and DeleteItem. Using conditional expressions with these operations, you can control how and under what conditions an item can be modified. You can prevent an update from occurring if the item does not meet some condition beforehand. For example, you can prevent PutItem from overwriting an existing item.

http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.SpecifyingConditions.html

The Model.create method sends a PutItem request which could be slightly misleading.

rafoli commented 7 years ago

Thanks @clarkie for your detailed answer.

I've changed my code to use a hashKey based on some fields, in that way, avoiding scan the table.

query.queryId = crypto.createHash('md5')
       .update(JSON.stringify({ email: query.email, name: query.name }))
       .digest("hex");   

So now, This { overwrite: false } suits my needs.

...create(query, { overwrite: false }, function(err, res) {