PHPackages                             justraviga/laravel-dynamodb-extreme - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Database &amp; ORM](/categories/database)
4. /
5. justraviga/laravel-dynamodb-extreme

ActiveLibrary[Database &amp; ORM](/categories/database)

justraviga/laravel-dynamodb-extreme
===================================

JustRaviga DynamoDb access package

v1.0.0(2y ago)13MITPHPPHP ^8.2

Since Jun 8Pushed 11mo ago1 watchersCompare

[ Source](https://github.com/JustRaviga/laravel-dynamodb-extreme)[ Packagist](https://packagist.org/packages/justraviga/laravel-dynamodb-extreme)[ RSS](/packages/justraviga-laravel-dynamodb-extreme/feed)WikiDiscussions develop Synced 1mo ago

READMEChangelogDependencies (6)Versions (3)Used By (0)

DynamoDb Query Builder
======================

[](#dynamodb-query-builder)

This is a Query Builder package for DynamoDb access. Inspired by other versions that didn't quite feel eloquent enough (see what I did there?), this one has the following features, just like Laravel:

---

#### Get a single Model instance from DynamoDb

[](#get-a-single-model-instance-from-dynamodb)

```
$model = Model::find($partitionKey, $sortKey);
```

Or, to throw `Illuminate\Database\Eloquent\ModelNotFoundException` if no results are returned:

```
$model = Model::findOrFail($partitionKey, $sortKey);
```

---

#### Get a Collection of Model instances from DynamoDb

[](#get-a-collection-of-model-instances-from-dynamodb)

Notes:

1. Only a single Model type is supported here. You must make sure your query will only return models of the same type.
2. An Exception will be thrown if a property found in the database is not in the $fillable array on the model.
3. DynamoDb only supports exact matches on Partition keys, and ``, `begins_with`, and `between`matches on Sort Keys.

```
/** @var DynamoDbResult $result */
$result = Model::where('partitionKey', $partitionKey)
    ->where('sortKey', 'begins_with', 'MODEL#')
    ->get();

/** @var \Illuminate\Support\Collection $models */
$models = $result->results;
```

You can optionally sort on the sortKey and limit the number of results:

```
/** @var DynamoDbResult $models */
$models = Model::where('partitionKey', $partitionKey)
    ->sortDescending()
    ->limit(10)
    ->get();
```

If you know you're going to exceed the 1mb query size limit of DynamoDb, you can use the `getAll()` method to make many queries until the entire result set is returned:

```
/** @var DynamoDbResult $models */
$models = Model::where('partitionKey', $partitionKey)
    ->getAll();
```

You can also get a specific set of results combining `limit()` and `after()`:

```
$twoResults = Model::where('partitionKey', $partitionKey)
    ->limit(2)
    ->get();

$twoMoreResults = Model::where('partitionKey', $partitionKey)
    ->after($twoResults->lastEvaluatedKey)
    ->limit(2)
    ->get();
```

A shortcut for this is built into the `paginate` method:

```
$twoResults = Model::where('partitionKey', $partitionKey)
    ->limit(2)
    ->paginate();

$twoMoreResults = Model::where('partitionKey', $partitionKey)
    ->limit(2)
    ->paginate($twoResults->lastEvaluatedKey());
```

---

#### Get a collection of models using a Secondary Index

[](#get-a-collection-of-models-using-a-secondary-index)

Provided the secondary index is configured (see below), it will be detected from the fields you are querying.

```
/** @var \Illuminate\Support\Collection $models */
$models = Model::where('index_partition_key', $partitionKey)
    ->where('index_sort_key', $sortKey)
    ->get();
```

---

#### Create a Model instance in DynamoDb

[](#create-a-model-instance-in-dynamodb)

Immediately persist the model with `create`:

```
$model = Model::create([
    'partitionKey' => 'value',
    'sortKey' => 'value',
    // other attributes...
]);
```

Build the model in memory without making a database query with `make`:

```
$model = Model::make([
    'partitionKey' => 'value',
    'sortKey' => 'sortKey',
    // other attributes...
]);

// persist the model
$model->save();
```

Alternatively use the `new Model()` syntax:

```
$model = new Model([
    'partitionKey' => 'value',
    'sortKey' => 'value',
    // other attributes
]);

// persist the model
$model->save();
```

---

#### Accessing Model attributes

[](#accessing-model-attributes)

Once you've created your model, attributes are accessed the same as you would with Laravel, using object property syntax:

```
$model = Model::find($partitionKey, $sortKey);

$model->someAttribute = 'value';
```

You can update many properties at the same time using the `fill` method:

```
$model = Model::find($partitionKey, $sortKey);
$model->fill([
    'someAttribute' => 'value',
    // other attributes
]);
```

These changes are not automatically persisted back to Dynamo, you need to save them manually:

```
$model = Model::find($partitionKey, $sortKey);

$model->someAttribute = 'value';
$model->save();
```

or

```
$model = Model::find($partitionKey, $sortKey);

$model->fill([
    'someAttribute' => 'value',
])->save();
```

or even, to combine `fill` and `save`:

```
$model = Model::find($partitionKey, $sortKey);

$model->update([
    'someAttribute' => 'value',
]);
```

Setup and global config
-----------------------

[](#setup-and-global-config)

### Environment variables

[](#environment-variables)

- `DYNAMODB_REGION` defaults to `localhost`, should be set to your main DynamoDb instance region (eu-west-2, for example)
- `DYNAMODB_VERSION` defaults to `latest`, should be set to the version of your DynamoDb instance if you need it
- `DYNAMODB_KEY` your DynamoDb access key (username)
- `DYNAMODB_SECRET` your DynamoDb secret (password)
- `DYNAMODB_ENDPOINT` defaults to `http://localhost:8000`, the address of your DynamoDb installation
- `DYNAMODB_TABLE` to define a default table for all models (useful when working with a single-table design in a specific application)
- `DYNAMODB_CONSISTENT_READ` defaults to `true`, use to set a default consistent read value (can still be overwritten by specific models)
- `DYNAMODB_LOG_QUERIES` defaults to `false`, use to add logging for all DynamoDb queries made (the json object being sent to Dynamo will be logged)

### Configuration options

[](#configuration-options)

The config file can be exported with Laravel's publish command: `php artisan vendor:publish`, it looks like this:

```
[
    'region' => env('DYNAMODB_REGION', 'localhost'),
    'version' => env('DYNAMODB_VERSION', 'latest'),
    'credentials' => [
        'key' => env('DYNAMODB_KEY', ''),
        'secret' => env('DYNAMODB_SECRET', ''),
    ],
    'endpoint' => env('DYNAMODB_ENDPOINT', 'http://localhost:8000'),
    'defaults' => [
        'consistent_read' => env('DYNAMODB_CONSISTENT_READ', true),
        'table' => env('DYNAMODB_TABLE', 'default'),
        'partition_key' => 'pk',
        'sort_key' => 'sk',
        'global_secondary_indexes' => [
            'gsi1' => [
                'pk' => 'gsi1_pk',
                'sk' => 'gsi1_sk',
            ]
        ],
        'log_queries' => env('DYNAMODB_LOG_QUERIES', false),
    ],
]
```

Apart from the environment-based config, here you can specify defaults for partition key, sort key, and global secondary indexes. These are intended to be sensible defaults based on general usage patterns of DynamoDb.

Model Configuration
-------------------

[](#model-configuration)

Creating a model is easy. At a bare minimum, you just need to define the table name, the partitionKey and sortKey, and an array of "fillable" attributes (note the partition and sort keys need to be fillable!):

```
class Model extends \DynamoDb\Models\DynamoDbModel
{
    // optional, see environment variable for table name
    protected string $table = 'models';

    // optional, see environment variable for partition/sort keys
    protected string $partitionKey = 'pk';
    protected string $sortKey = 'sk';

    // required!  must include at least partition/sort keys
    public array $fillable = [
        'pk',
        'sk',
        // other attributes...
    ];
}
```

---

To write more verbose code, you can create a mapping from internal/database fields to friendly attributes by overriding the `fieldMappings` protected property. The mappings are applied when fetching from the database and when saving to the database. The rest of the time, you always use the mapped property name.

```
class Model extends \DynamoDb\Models\DynamoDbModel
{
    // optional
    protected array $fieldMappings = [
        'pk' => 'my_uuid',
        'sk' => 'created_date',
    ];
}
```

---

By default, all models' Partition Keys are built with the model class name followed by a `#` then a UUID-7 (time-ordered UUID). Sort Keys default to the model name. For example:

```
class Model extends \DynamoDb\Models\DynamoDbModel { }

$model = new Model();
// partition key = 'MODEL#{uuid-7}
// sort key = 'MODEL'
```

You can also change these default values when creating new models by overriding these methods:

```
class Model extends \DynamoDb\Models\DynamoDbModel
{
    public function defaultPartitionKey(): string
    {
        return 'MODEL#' . random_int(0,1000);
    }

    public function defaultSortKey(): string
    {
        return 'CREATED_AT#' . now()->toISOString();
    }

    public function defaultValues(): array
    {
        return [
            'attribute' => 'default value',
        ];
    }
}
```

### Related models

[](#related-models)

You can configure related models that share the same Partition Key with some minor extra setup:

```
class ParentModel extends \DynamoDb\Models\DynamoDbModel
{
    public function childModels(): \DynamoDb\DynamoDb\Relation
    {
        return $this->addRelation(ChildModel::class);
    }
}
```

By default, this uses the Partition key of the parent model, and matches on the Sort key with a "begins\_with" query against the child model's class name followed by a hash (#), something like `begins_with(sk, 'CHILDMODEL#')`. The matching itself can be configured on the child models by overriding the `relationSearchParams` method:

```
class ChildModel extends \DynamoDb\Models\DynamoDbModel
{
    public static function relationSearchParams(): array
    {
        return [
            'sk',
            'begins_with',
            'CLASSNAME#'
        ];
    }
}
```

The related models can be accessed as a Collection using a property of the same name as the relationship method, e.g:

```
class Model extends \DynamoDb\Models\DynamoDbModel
{
    public function children(): \DynamoDb\DynamoDb\Relation
    {
        return $this->addRelation(Child::class);
    }
}

$model = Model::find(...);

$model->children->map(fn ($child) => $child->doSomething());
```

#### "inline" relations

[](#inline-relations)

In addition to using different rows in a DynamoDb table to hold related models, you can use a JSON attribute on a record as a relation. We call this an "inline relation" and they can be accessed the same way as other relations:

```
class Model extends \DynamoDb\Models\DynamoDbModel
{
    public function inline(): InlineRelation
    {
        return $this->addInlineRelation(Inline::class, 'inline');
    }
}

$model = Model::find(...);

$model->inline->map(fn ($child) => $child->doSomething());
```

---

If you want to use a secondary index on your table, just define the Partition and Sort Key names in the `$indexes` array. Be sure to add them to the `$fillable` array as well.

```
class Model extends \DynamoDb\Models\DynamoDbModel
{
    // optional, see config values
    protected array $indexes = [
        'gsi1' => [
            'pk' => 'gsi1_pk',
            'sk' => 'gsi1_sk',
        ],
    ];

    // required if you want to use a secondary index
    public array $fillable = [
        'gsi1_pk',
        'gsi1_sk',
        // other attributes...
    ];
}
```

---

You can define mappings from secondary indexes to friendly model properties in the `$fieldMappings` array too.

```
class Model extends \JustRaviga\LaravelDynamodbExtreme\Models\DynamoDbModel
{
    // optional
    protected array $fieldMappings = [
        'gsi1_pk' => 'user_uuid',
        'gsi1_sk' => 'created_date',
    ];
}
```

Minimum Requirements
--------------------

[](#minimum-requirements)

1. PHP 8.2
2. Laravel 10.0

Wishlist
--------

[](#wishlist)

The things we might like to include (eventually) but didn't have time to properly consider:

> Wrapping DynamoDb responses in a cache layer

Optionally have models fetched from DynamoDb stored in memory for the duration of the request so multiple calls to the same partition/sort key return the same data without querying Dynamo.

> Attribute casts

Similar to the Laravel model $casts array, attributes should be coerced to/from these data types when fetching and saving with DynamoDb.

> Extend the Collection class to include filter methods based on DynamoDb models

Potential for new methods on the Collection class for pagination based on the Last Evaluated Key from DynamoDb.

> Better documentation 🙈

Docs can always be improved.

> Concurrent requests

Figure out how to make many concurrent requests that can be *awaited* and only continue execution once all of the requests have returned their data.

> Table generation in code

Essentially Laravel's migration system for DynamoDb tables

> Cascade deletions

Delete related models after deleting a parent model

###  Health Score

30

—

LowBetter than 64% of packages

Maintenance38

Infrequent updates — may be unmaintained

Popularity5

Limited adoption so far

Community9

Small or concentrated contributor base

Maturity58

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 97.6% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

1069d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/b8ca566de4400c8eead7ed9debed897d5b99d2231b7a1543063c999d5c5ee9ba?d=identicon)[JustRaviga](/maintainers/JustRaviga)

---

Top Contributors

[![robw-raviga](https://avatars.githubusercontent.com/u/132554132?v=4)](https://github.com/robw-raviga "robw-raviga (40 commits)")[![MPJHorner](https://avatars.githubusercontent.com/u/4990716?v=4)](https://github.com/MPJHorner "MPJHorner (1 commits)")

###  Code Quality

TestsPest

### Embed Badge

![Health badge](/badges/justraviga-laravel-dynamodb-extreme/health.svg)

```
[![Health](https://phpackages.com/badges/justraviga-laravel-dynamodb-extreme/health.svg)](https://phpackages.com/packages/justraviga-laravel-dynamodb-extreme)
```

###  Alternatives

[anourvalar/eloquent-serialize

Laravel Query Builder (Eloquent) serialization

11320.2M21](/packages/anourvalar-eloquent-serialize)[leantime/leantime

Open source project management system for non-project managers. Simple like Trello, powerful like Jira. Built with neurodiversity in mind.

9.4k2.8k](/packages/leantime-leantime)[overtrue/laravel-versionable

Make Laravel model versionable.

585308.0k5](/packages/overtrue-laravel-versionable)[abbasudo/laravel-purity

elegant way to add filter and sort in laravel

514330.5k1](/packages/abbasudo-laravel-purity)[statamic-rad-pack/runway

Eloquently manage your database models in Statamic.

135192.6k5](/packages/statamic-rad-pack-runway)[dragon-code/laravel-deploy-operations

Performing any actions during the deployment process

240173.5k2](/packages/dragon-code-laravel-deploy-operations)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
