2017 © Pedro Peláez
 

library dynamodb

Eloquent syntax for DynamoDB

image

baopham/dynamodb

Eloquent syntax for DynamoDB

  • Friday, July 6, 2018
  • by baopham
  • Repository
  • 16 Watchers
  • 137 Stars
  • 91,950 Installations
  • PHP
  • 2 Dependents
  • 0 Suggesters
  • 48 Forks
  • 1 Open issues
  • 67 Versions
  • 18 % Grown

The README.md

laravel-dynamodb

Latest Stable Version Total Downloads Latest Unstable Version Build Status Code Coverage License, (*1)

Supports all key types - primary hash key and composite keys., (*2)

For advanced users only. If you're not familiar with Laravel, Laravel Eloquent and DynamoDB, then I suggest that you get familiar with those first., (*3)

Breaking changes in v2: config no longer lives in config/services.php, (*4)

Install

  • Composer install, (*5)

    composer require baopham/dynamodb
    
  • Install service provider (< Laravel 5.5):, (*6)

    // config/app.php
    
    'providers' => [
        ...
        BaoPham\DynamoDb\DynamoDbServiceProvider::class,
        ...
    ];
    
  • Run, (*7)

    php artisan vendor:publish --provider 'BaoPham\DynamoDb\DynamoDbServiceProvider'
    
  • Update DynamoDb config in config/dynamodb.php, (*8)

For Lumen, (*9)

  • Try this to install the vendor:publish command, (*10)

  • Load configuration file and enable Eloquent support in bootstrap/app.php:, (*11)

    $app = new Laravel\Lumen\Application(
      realpath(__DIR__.'/../')
    );
    
    // Load dynamodb config file
    $app->configure('dynamodb');
    
    // Enable Facade support
    $app->withFacades();
    
    // Enable Eloquent support
    $app->withEloquent();
    

Usage

  • Extends your model with BaoPham\DynamoDb\DynamoDbModel, then you can use Eloquent methods that are supported. The idea here is that you can switch back to Eloquent without changing your queries.
  • Or if you want to sync your DB table with a DynamoDb table, use trait BaoPham\DynamoDb\ModelTrait, it will call a PutItem after the model is saved.
  • Alternatively, you can use the query builder facade to build more complex queries.
  • AWS SDK v3 for PHP uses guzzlehttp promises to allow for asynchronous workflows. Using this package you can run eloquent queries like delete, update, save asynchronously on DynamoDb.

Supported features:

find() and delete()

$model->find($id, array $columns = []);
$model->findMany($ids, array $columns = []);
$model->delete();
$model->deleteAsync()->wait();

Conditions

// Using getIterator()
// If 'key' is the primary key or a global/local index and it is a supported Query condition,
// will use 'Query', otherwise 'Scan'.
$model->where('key', 'key value')->get();

$model->where(['key' => 'key value']);

// Chainable for 'AND'.
$model->where('foo', 'bar')
    ->where('foo2', '!=', 'bar2')
    ->get();

// Chainable for 'OR'.
$model->where('foo', 'bar')
    ->orWhere('foo2', '!=', 'bar2')
    ->get();

// Other types of conditions
$model->where('count', '>', 0)->get();
$model->where('count', '>=', 0)->get();
$model->where('count', '<', 0)->get();
$model->where('count', '<=', 0)->get();
$model->whereIn('count', [0, 100])->get();
$model->whereNotIn('count', [0, 100])->get();
$model->where('count', 'between', [0, 100])->get();
$model->where('description', 'begins_with', 'foo')->get();
$model->where('description', 'contains', 'foo')->get();
$model->where('description', 'not_contains', 'foo')->get();

// Nested conditions
$model->where('name', 'foo')
    ->where(function ($query) {
        $query->where('count', 10)->orWhere('count', 20);
    })
    ->get();

// Nested attributes
$model->where('nestedMap.foo', 'bar')->where('list[0]', 'baz')->get();
whereNull() and whereNotNull()

NULL and NOT_NULL only check for the attribute presence not its value being null
See: http://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Condition.html, (*12)

$model->whereNull('name');
$model->whereNotNull('name');

all() and first()

// Using scan operator, not too reliable since DynamoDb will only give 1MB total of data.
$model->all();

// Basically a scan but with limit of 1 item.
$model->first();

Pagination

Unfortunately, offset of how many records to skip does not make sense for DynamoDb. Instead, provide the last result of the previous query as the starting point for the next query., (*13)

Examples:, (*14)

For query such as:, (*15)

$query = $model->where('count', 10)->limit(2);
$items = $query->all();
$last = $items->last();

Take the last item of this query result as the next "offset":, (*16)

$nextPage = $query->after($last)->limit(2)->all();
// or
$nextPage = $query->afterKey($items->lastKey())->limit(2)->all();
// or (for query without index condition only)
$nextPage = $query->afterKey($last->getKeys())->limit(2)->all();

update()

// update
$model->update($attributes);

updateAsync()

// update asynchronously and wait on the promise for completion.
$model->updateAsync($attributes)->wait();

save()

$model = new Model();
// Define fillable attributes in your Model class.
$model->fillableAttr1 = 'foo';
$model->fillableAttr2 = 'foo';
// DynamoDb doesn't support incremented Id, so you need to use UUID for the primary key.
$model->id = 'de305d54-75b4-431b-adb2-eb6b9e546014';
$model->save();

saveAsync()

Saving single model asynchronously and waiting on the promise for completion., (*17)

$model = new Model();
// Define fillable attributes in your Model class.
$model->fillableAttr1 = 'foo';
$model->fillableAttr2 = 'bar';
// DynamoDb doesn't support incremented Id, so you need to use UUID for the primary key.
$model->id = 'de305d54-75b4-431b-adb2-eb6b9e546014';
$model->saveAsync()->wait();

Saving multiple models asynchronously and waiting on all of them simultaneously., (*18)

for($i = 0; $i < 10; $i++){
    $model = new Model();
    // Define fillable attributes in your Model class.
    $model->fillableAttr1 = 'foo';
    $model->fillableAttr2 = 'bar';
    // DynamoDb doesn't support incremented Id, so you need to use UUID for the primary key.
    $model->id = uniqid();
    // Returns a promise which you can wait on later.
    $promises[] = $model->saveAsync();
}

\GuzzleHttp\Promise\all($promises)->wait();

delete()

$model->delete();

deleteAsync()

$model->deleteAsync()->wait();

chunk()

$model->chunk(10, function ($records) {
    foreach ($records as $record) {

    }
});

limit() and take()

// Use this with caution unless your limit is small.
// DynamoDB has a limit of 1MB so if your limit is very big, the results will not be expected.
$model->where('name', 'foo')->take(3)->get();

firstOrFail()

$model->where('name', 'foo')->firstOrFail();
// for composite key
$model->where('id', 'foo')->where('id2', 'bar')->firstOrFail();

findOrFail()

$model->findOrFail('foo');
// for composite key
$model->findOrFail(['id' => 'foo', 'id2' => 'bar']);

refresh()

$model = Model::first();
$model->refresh();

Query Scope

class Foo extends DynamoDbModel
{
    protected static function boot()
    {
        parent::boot();

        static::addGlobalScope('count', function (DynamoDbQueryBuilder $builder) {
            $builder->where('count', '>', 6);
        });
    }

    public function scopeCountUnderFour($builder)
    {
        return $builder->where('count', '<', 4);
    }

    public function scopeCountUnder($builder, $count)
    {
        return $builder->where('count', '<', $count);
    }
}

$foo = new Foo();
// Global scope will be applied
$foo->all();
// Local scope
$foo->withoutGlobalScopes()->countUnderFour()->get();
// Dynamic local scope
$foo->withoutGlobalScopes()->countUnder(6)->get();

REMOVE — Deleting Attributes From An Item

See: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.UpdateExpressions.html#Expressions.UpdateExpressions.REMOVE, (*19)

$model = new Model();
$model->where('id', 'foo')->removeAttribute('name', 'description', 'nested.foo', 'nestedArray[0]');

// Or
Model::find('foo')->removeAttribute('name', 'description', 'nested.foo', 'nestedArray[0]');

toSql() Style

For debugging purposes, you can choose to convert to the actual DynamoDb query, (*20)

$raw = $model->where('count', '>', 10)->toDynamoDbQuery();
// $op is either "Scan" or "Query"
$op = $raw->op;
// The query body being sent to AWS
$query = $raw->query;

where $raw is an instance of RawDynamoDbQuery, (*21)

Decorate Query

Use decorate when you want to enhance the query. For example:, (*22)

To set the order of the sort key:, (*23)

$items = $model
    ->where('hash', 'hash-value')
    ->where('range', '>', 10)
    ->decorate(function (RawDynamoDbQuery $raw) {
        // desc order
        $raw->query['ScanIndexForward'] = false;
    })
    ->get();

To force to use "Query" instead of "Scan" if the library fails to detect the correct operation:, (*24)

$items = $model
    ->where('hash', 'hash-value')
    ->decorate(function (RawDynamoDbQuery $raw) {
        $raw->op = 'Query';
    })
    ->get();

Indexes

If your table has indexes, make sure to declare them in your model class like so, (*25)

/**
 * Indexes.
 * [
 *     '<simple_index_name>' => [
 *          'hash' => '<index_key>'
 *     ],
 *     '<composite_index_name>' => [
 *          'hash' => '<index_hash_key>',
 *          'range' => '<index_range_key>'
 *     ],
 * ]
 *
 * @var array
 */
protected $dynamoDbIndexKeys = [
    'count_index' => [
        'hash' => 'count'
    ],
];

Note that order of index matters when a key exists in multiple indexes.
For example, we have this, (*26)

$model->where('user_id', 123)->where('count', '>', 10)->get();

with, (*27)

protected $dynamoDbIndexKeys = [
    'count_index' => [
        'hash' => 'user_id',
        'range' => 'count'
    ],
    'user_index' => [
        'hash' => 'user_id',
    ],
];

will use count_index., (*28)

protected $dynamoDbIndexKeys = [
    'user_index' => [
        'hash' => 'user_id',
    ],
    'count_index' => [
        'hash' => 'user_id',
        'range' => 'count'
    ]
];

will use user_index., (*29)

Most of the time, you should not have to do anything but if you need to use a specific index, you can specify it like so, (*30)

$model->where('user_id', 123)->where('count', '>', 10)->withIndex('count_index')->get();

Composite Keys

To use composite keys with your model:, (*31)

  • Set $compositeKey to an array of the attributes names comprising the key, e.g.
protected $primaryKey = 'customer_id';
protected $compositeKey = ['customer_id', 'agent_id'];
  • To find a record with a composite key
$model->find(['customer_id' => 'value1', 'agent_id' => 'value2']);

Query Builder

Use DynamoDb facade to build raw queries, (*32)

use BaoPham\DynamoDb\Facades\DynamoDb;

DynamoDb::table('articles')
    // call set<key_name> to build the query body to be sent to AWS
    ->setFilterExpression('#name = :name')
    ->setExpressionAttributeNames(['#name' => 'author_name'])
    ->setExpressionAttributeValues([':name' => DynamoDb::marshalValue('Bao')])
    ->prepare()
    // the query body will be sent upon calling this.
    ->scan(); // supports any DynamoDbClient methods (e.g. batchWriteItem, batchGetItem, etc.)

DynamoDb::table('articles')
    ->setIndexName('author_name')
    ->setKeyConditionExpression('#name = :name')
    ->setProjectionExpression('id, author_name')
    // Can set the attribute mapping one by one instead
    ->setExpressionAttributeName('#name', 'author_name')
    ->setExpressionAttributeValue(':name', DynamoDb::marshalValue('Bao'))
    ->prepare()
    ->query();

DynamoDb::table('articles')
    ->setKey(DynamoDb::marshalItem(['id' => 'ae025ed8']))
    ->setUpdateExpression('REMOVE #c, #t')
    ->setExpressionAttributeName('#c', 'comments')
    ->setExpressionAttributeName('#t', 'tags')
    ->prepare()
    ->updateItem();

DynamoDb::table('articles')
    ->setKey(DynamoDb::marshalItem(['id' => 'ae025ed8']))
    ->prepare()
    ->deleteItem();

DynamoDb::table('articles')
    ->setItem(DynamoDb::marshalItem(['id' => 'ae025ed8', 'author_name' => 'New Name']))
    ->prepare()
    ->putItem();

// Or, instead of ::table()
DynamoDb::newQuery()
    ->setTableName('articles')

// Or access the DynamoDbClient instance directly
DynamoDb::client();
// pass in the connection name to get a different client instance other than the default.
DynamoDb::client('test');

The query builder methods are in the form of set<key_name>, where <key_name> is the key name of the query body to be sent., (*33)

For example, to build an UpdateTable query:, (*34)

[
    'AttributeDefinitions' => ...,
    'GlobalSecondaryIndexUpdates' => ...,
    'TableName' => ...
]

Do:, (*35)

$query = DynamoDb::table('articles')
    ->setAttributeDefinitions(...)
    ->setGlobalSecondaryIndexUpdates(...);

And when ready:, (*36)

$query->prepare()->updateTable();

Requirements

Laravel ^5.1, (*37)

Migrate from v1 to v2

Follow these steps:, (*38)

  1. Update your composer.json to use v2
  2. Run composer update
  3. Run php artisan vendor:publish
  4. Move your DynamoDb config in config/services.php to the new config file config/dynamodb.php as one of the connections
    1. Move key, secret, token inside credentials
    2. Rename local_endpoint to endpoint
    3. Remove local field

FAQ

Q: Cannot assign id property if its not in the fillable array
A: Try this?, (*39)

Q: How to create migration?
A: Please see this issue, (*40)

Q: How to use with factory?
A: Please see this issue, (*41)

Q: How do I use with Job? Getting a SerializesModels error
A: You can either write your own restoreModel or remove the SerializesModels trait from your Job., (*42)

Author and Contributors

The Versions

04/07 2018

dev-feature/127-after-supports-raw-value

dev-feature/127-after-supports-raw-value

Eloquent syntax for DynamoDB

  Sources   Download

MIT

The Requires

 

The Development Requires

laravel aws dynamodb

29/01 2018

4.2.2

4.2.2.0

Eloquent syntax for DynamoDB

  Sources   Download

MIT

The Requires

 

The Development Requires

laravel aws dynamodb

23/01 2018

4.2.1

4.2.1.0

Eloquent syntax for DynamoDB

  Sources   Download

MIT

The Requires

 

The Development Requires

laravel aws dynamodb

06/01 2018

4.2.0

4.2.0.0

Eloquent syntax for DynamoDB

  Sources   Download

MIT

The Requires

 

The Development Requires

laravel aws dynamodb

29/11 2017

4.1.1

4.1.1.0

Eloquent syntax for DynamoDB

  Sources   Download

MIT

The Requires

 

The Development Requires

laravel aws dynamodb

25/11 2017

4.1.0

4.1.0.0

Eloquent syntax for DynamoDB

  Sources   Download

MIT

The Requires

 

The Development Requires

laravel aws dynamodb

25/11 2017

4.0.0

4.0.0.0

Eloquent syntax for DynamoDB

  Sources   Download

MIT

The Requires

 

The Development Requires

laravel aws dynamodb

24/11 2017

3.0.1

3.0.1.0

Eloquent syntax for DynamoDB

  Sources   Download

MIT

The Requires

 

The Development Requires

laravel aws dynamodb

24/11 2017

3.0.0

3.0.0.0

Eloquent syntax for DynamoDB

  Sources   Download

MIT

The Requires

 

The Development Requires

laravel aws dynamodb

19/10 2017

2.0.3

2.0.3.0

Eloquent syntax for DynamoDB

  Sources   Download

MIT

The Requires

 

The Development Requires

laravel aws dynamodb

19/10 2017

v1.x-dev

1.9999999.9999999.9999999-dev

Eloquent syntax for DynamoDB

  Sources   Download

MIT

The Requires

 

The Development Requires

laravel aws dynamodb

19/10 2017

1.7.3

1.7.3.0

Eloquent syntax for DynamoDB

  Sources   Download

MIT

The Requires

 

The Development Requires

laravel aws dynamodb

19/10 2017

2.0.2

2.0.2.0

Eloquent syntax for DynamoDB

  Sources   Download

MIT

The Requires

 

The Development Requires

laravel aws dynamodb

19/10 2017

1.7.2

1.7.2.0

Eloquent syntax for DynamoDB

  Sources   Download

MIT

The Requires

 

The Development Requires

laravel aws dynamodb

19/10 2017

2.0.1

2.0.1.0

Eloquent syntax for DynamoDB

  Sources   Download

MIT

The Requires

 

The Development Requires

laravel aws dynamodb

19/10 2017

1.7.1

1.7.1.0

Eloquent syntax for DynamoDB

  Sources   Download

MIT

The Requires

 

The Development Requires

laravel aws dynamodb

16/10 2017

2.0.0

2.0.0.0

Eloquent syntax for DynamoDB

  Sources   Download

MIT

The Requires

 

The Development Requires

laravel aws dynamodb

30/09 2017

1.7.0

1.7.0.0

Eloquent syntax for DynamoDB

  Sources   Download

MIT

The Requires

 

The Development Requires

laravel aws dynamodb

21/08 2017

1.6.1

1.6.1.0

Eloquent syntax for DynamoDB

  Sources   Download

MIT

The Requires

 

The Development Requires

laravel aws dynamodb

21/08 2017

1.6.0

1.6.0.0

Eloquent syntax for DynamoDB

  Sources   Download

MIT

The Requires

 

The Development Requires

laravel aws dynamodb

18/08 2017

1.5.0

1.5.0.0

Eloquent syntax for DynamoDB

  Sources   Download

MIT

The Requires

 

The Development Requires

laravel aws dynamodb

17/08 2017

1.4.0

1.4.0.0

Eloquent syntax for DynamoDB

  Sources   Download

MIT

The Requires

 

The Development Requires

laravel aws dynamodb

17/08 2017

1.3.0

1.3.0.0

Eloquent syntax for DynamoDB

  Sources   Download

MIT

The Requires

 

The Development Requires

laravel aws dynamodb

14/08 2017

1.2.0

1.2.0.0

Eloquent syntax for DynamoDB

  Sources   Download

MIT

The Requires

 

The Development Requires

laravel aws dynamodb

14/08 2017

1.1.0

1.1.0.0

DynamoDb wrapper for your Laravel model and helpers

  Sources   Download

MIT

The Requires

 

The Development Requires

laravel aws dynamodb

13/08 2017

1.0.0

1.0.0.0

DynamoDb wrapper for your Laravel model and helpers

  Sources   Download

MIT

The Requires

 

The Development Requires

laravel aws dynamodb

13/08 2017

0.10.0

0.10.0.0

DynamoDb wrapper for your Laravel model and helpers

  Sources   Download

MIT

The Requires

 

The Development Requires

laravel aws dynamodb

13/08 2017

dev-whereNull

dev-whereNull

DynamoDb wrapper for your Laravel model and helpers

  Sources   Download

MIT

The Requires

 

The Development Requires

laravel aws dynamodb

12/08 2017

0.9.0

0.9.0.0

DynamoDb wrapper for your Laravel model and helpers

  Sources   Download

MIT

The Requires

 

The Development Requires

laravel aws dynamodb

12/08 2017

0.8.0

0.8.0.0

DynamoDb wrapper for your Laravel model and helpers

  Sources   Download

MIT

The Requires

 

The Development Requires

laravel aws dynamodb

12/08 2017

0.7.0

0.7.0.0

DynamoDb wrapper for your Laravel model and helpers

  Sources   Download

MIT

The Requires

 

The Development Requires

laravel aws dynamodb

12/08 2017

0.6.2

0.6.2.0

DynamoDb wrapper for your Laravel model and helpers

  Sources   Download

MIT

The Requires

 

The Development Requires

laravel aws dynamodb

12/08 2017

0.6.1

0.6.1.0

DynamoDb wrapper for your Laravel model and helpers

  Sources   Download

MIT

The Requires

 

The Development Requires

laravel aws dynamodb

06/08 2017

0.6.0

0.6.0.0

DynamoDb wrapper for your Laravel model and helpers

  Sources   Download

MIT

The Requires

 

The Development Requires

laravel aws dynamodb

06/08 2017

dev-fix-composite-condition

dev-fix-composite-condition

DynamoDb wrapper for your Laravel model and helpers

  Sources   Download

MIT

The Requires

 

The Development Requires

laravel aws dynamodb

07/07 2017

0.5.1

0.5.1.0

DynamoDb wrapper for your Laravel model and helpers

  Sources   Download

MIT

The Requires

 

The Development Requires

laravel aws dynamodb

23/06 2017

0.5.0

0.5.0.0

DynamoDb wrapper for your Laravel model and helpers

  Sources   Download

MIT

The Requires

 

The Development Requires

laravel aws dynamodb

22/06 2017

0.4.2

0.4.2.0

DynamoDb wrapper for your Laravel model and helpers

  Sources   Download

MIT

The Requires

 

The Development Requires

laravel aws dynamodb

16/06 2017

0.4.1

0.4.1.0

DynamoDb wrapper for your Laravel model and helpers

  Sources   Download

MIT

The Requires

 

The Development Requires

laravel aws dynamodb

26/12 2016

0.4.0

0.4.0.0

DynamoDb wrapper for your Laravel model and helpers

  Sources   Download

MIT

The Requires

 

The Development Requires

laravel aws dynamodb

25/11 2016

dev-test-circleci

dev-test-circleci

DynamoDb wrapper for your Laravel model and helpers

  Sources   Download

MIT

The Requires

 

The Development Requires

laravel aws dynamodb

24/11 2016

dev-test-travis

dev-test-travis

DynamoDb wrapper for your Laravel model and helpers

  Sources   Download

MIT

The Requires

 

The Development Requires

laravel aws dynamodb

24/11 2016

0.3.2

0.3.2.0

DynamoDb wrapper for your Laravel model and helpers

  Sources   Download

MIT

The Requires

 

The Development Requires

laravel aws dynamodb

28/09 2016

0.3.1

0.3.1.0

DynamoDb wrapper for your Laravel model and helpers

  Sources   Download

MIT

The Requires

 

The Development Requires

laravel aws dynamodb

25/05 2016

0.3.0

0.3.0.0

DynamoDb wrapper for your Laravel model and helpers

  Sources   Download

MIT

The Requires

 

The Development Requires

laravel aws dynamodb

06/05 2016

0.2.3

0.2.3.0

DynamoDb wrapper for your Laravel model and helpers

  Sources   Download

MIT

The Requires

 

The Development Requires

laravel aws dynamodb

06/05 2016

dev-query-builder

dev-query-builder

DynamoDb wrapper for your Laravel model and helpers

  Sources   Download

MIT

The Requires

 

The Development Requires

laravel aws dynamodb

09/04 2016

0.2.2

0.2.2.0

DynamoDb wrapper for your Laravel model and helpers

  Sources   Download

MIT

The Requires

 

The Development Requires

laravel aws dynamodb

09/04 2016

0.2.1

0.2.1.0

DynamoDb wrapper for your Laravel model and helpers

  Sources   Download

MIT

The Requires

 

The Development Requires

laravel aws dynamodb

27/02 2016

0.2.0

0.2.0.0

DynamoDb wrapper for your Laravel model and helpers

  Sources   Download

MIT

The Requires

 

The Development Requires

laravel aws dynamodb

05/01 2016

0.1.2

0.1.2.0

DynamoDb wrapper for your Laravel model and helpers

  Sources   Download

MIT

The Requires

 

The Development Requires

laravel aws dynamodb

22/11 2015

0.1.1

0.1.1.0

DynamoDb wrapper for your Laravel model and helpers

  Sources   Download

MIT

The Requires

 

The Development Requires

laravel aws dynamodb

04/08 2015

0.1.0

0.1.0.0

DynamoDb wrapper for your Laravel model and helpers

  Sources   Download

MIT

The Requires

 

The Development Requires