awslabs / dynamodb-data-mapper-js

A schema-based data mapper for Amazon DynamoDB.
https://awslabs.github.io/dynamodb-data-mapper-js/
Apache License 2.0
817 stars 106 forks source link

Can I ask for a better example in the expressions package? #90

Open LucasBadico opened 6 years ago

LucasBadico commented 6 years ago

I really have been strugly to undestand how to use it. For example, I need to make my dynamodb just make a update(acting as a create) if there is no username. I know that to doing that I have to do this:

dynamodb.putItem({
            TableName: config.DDB_TABLE,
            Item: {
                email: {
                    S: email
                },
                passwordHash: {
                    S: password
                },
                passwordSalt: {
                    S: salt
                },
                verified: {
                    BOOL: false
                },
                verifyToken: {
                    S: token
                }
            },
            ConditionExpression: 'attribute_not_exists (email)'
        }, function(err, data) {
            if (err) return fn(err);
            else fn(null, token);
        });

How I make this a operation with the mapper and expressions lib?

jeskew commented 6 years ago

If you have a class defined as:

@table(config.DDB_TABLE)
class MyRecord {
    @hashKey()
    email?: string;

    @attribute()
    passwordHash?: string;

    @attribute()
    passwordSalt?: string;

    @attribute()
    verified?: boolean;

    @attribute()
    verifyToken?: string;
}

Then you could execute the update as:


const aRecord = Object.assign(new MyRecord(), {
    email,
    passwordHash: password,
    passwordSalt: salt,
    verified: false,
    verifyToken: token,
});
mapper.put(aRecord, { 
    condition: new FunctionExpression('attribute_not_exists', new AttributePath('email') 
}).then( /* result handler */ );
LucasBadico commented 6 years ago

Can I put this on the readme of expressions?

LucasBadico commented 6 years ago

Hey guys. testing this here is not working, still add a new item with the same email.

LucasBadico commented 6 years ago

@jeskew a funny thing... look at this...

This is my test. It is not working as expected...

import {
    FunctionExpression,
    AttributePath,
} from '@aws/dynamodb-expressions'

import { User, connection, Repository } from '../src/domain-user'

const user = new User({
    accountId: '2e2b043f-47e2-40d8-878d-829bc06af003',
    // username: 'customer-123',
    createdAt: (new Date()).toString()
})
console.log(new FunctionExpression('attribute_not_exists', new AttributePath('accountId')))
connection.mapper.put(user, { 
    condition: new FunctionExpression('attribute_not_exists', new AttributePath('accountId'))
}).then(console.log).catch(console.error)
{ ConditionalCheckFailedException: The conditional request failed
    at Request.extractError (/developer/project/node_modules/aws-sdk/lib/protocol/json.js:48:27)
    at Request.callListeners (/developer/project/node_modules/aws-sdk/lib/sequential_executor.js:105:20)
    at Request.emit (/developer/project/node_modules/aws-sdk/lib/sequential_executor.js:77:10)
    at Request.emit (/developer/project/node_modules/aws-sdk/lib/request.js:683:14)
    at Request.transition (/developer/project/node_modules/aws-sdk/lib/request.js:22:10)
    at AcceptorStateMachine.runTo (/developer/project/node_modules/aws-sdk/lib/state_machine.js:14:12)
    at /developer/project/node_modules/aws-sdk/lib/state_machine.js:26:10
    at Request.<anonymous> (/developer/project/node_modules/aws-sdk/lib/request.js:38:9)
    at Request.<anonymous> (/developer/project/node_modules/aws-sdk/lib/request.js:685:12)
    at Request.callListeners (/developer/project/node_modules/aws-sdk/lib/sequential_executor.js:115:18)
  message: 'The conditional request failed',
  code: 'ConditionalCheckFailedException',
  time: 2018-08-18T01:48:50.981Z,
  requestId: 'GBLH99R2PTHE65M97OF7LI48URVV4KQNSO5AEMVJF66Q9ASUAAJG',
  statusCode: 400,
  retryable: false,
  retryDelay: 26.5584118220047 }

it is aways throwing this error. And is writing a new item every time.

LucasBadico commented 6 years ago

Still struggling... but now I think that is more straight foword aswer. I have this filter operation:

export function getByCpf({ cpf, merchantId}) {
    return new Promise((resolve, reject) => this.client.query({
            TableName: tableName,
            KeyConditionExpression: "merchantId = :id",
            FilterExpression: 'documents[0].documentNumber = :cpf',
            ExpressionAttributeValues: {
                ":cpf" : {
                    S: cpf,
                },
                ":id": {
                    S: merchantId,
                }
            }
        }, (err, {Items}) => {
            if (err) {
                return reject(err)
            }
            return resolve(Items)
        })
    )
}

How use the filter on the data mapper?

await mapper.get(myClass, {filter: ???})
puzzloholic commented 6 years ago

I have been playing with these library for a while, this is my proposed function using datamapper. I don't know whether documents[0].documentNumber will fail the function or not, as I never encounter such key before.

import { equals } from '@aws/dynamodb-expressions';
export async function getByCpf({ cpf, merchantId }) {
    const keyCondition = {
        merchantId: merchantId,
    }
    const predicate = equals(cpf);
    const filterCondition = {
        ...predicate,
        subject: 'documents[0].documentNumber'
    }
    const queryOptions = {
        filter: filterCondition
    }
    const iterator = mapper.query(myClass, keyCondition, queryOptions);
    let result = [];
    for await (const record of iterator) {
        result.push(record);
    }

    return result;
}

queryOptions will be translated as follows :

queryOptions = {
    filter:
    {
        type: 'Equals',
        object: cpf,
        subject: 'documents[0].documentNumber'
    }
}

You can find full documentation about other expression here https://awslabs.github.io/dynamodb-data-mapper-js/packages/dynamodb-expressions/

LucasBadico commented 6 years ago

Nice! Thanks @puzzloholic I will implement

johndoe2361289638163 commented 5 years ago

How would you use the FunctionExpression with the 'size'-Function? The following is not working unfortunately. https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html#Expressions.OperatorsAndFunctions.Functions

new FunctionExpression('size', new AttributePath('aAttributeWithStringSetAsType'), '> 0')