The DynamoDB Toolbox is a set of tools that makes it easy to work with Amazon DynamoDB and the DocumentClient. It's designed with Single Tables in mind, but works just as well with multiple tables. It lets you define your Entities (with typings and aliases) and map them to your DynamoDB tables. You can then generate the API parameters to put
, get
, delete
, update
, query
, scan
, batchGet
, and batchWrite
data by passing in JavaScript objects. The DynamoDB Toolbox will map aliases, validate and coerce types, and even write complex UpdateExpression
s for you. ๐
v0.4 is here and now supports "Type Inferencing" ๐. This is a new feature that infers types from your Entity definitions. There should be NO regressions from v0.3.5, but please submit an issue if you find one!
Feedback is welcome and much appreciated! (Huge thanks to @ThomasAribart for all his work on this ๐)
Install DynamoDB Toolbox:
# npm
npm i dynamodb-toolbox
# yarn
yarn add dynamodb-toolbox
Require or import Table
and Entity
from dynamodb-toolbox
:
import { Table, Entity } from 'dynamodb-toolbox'
Create a Table (with the DocumentClient):
import DynamoDB from 'aws-sdk/clients/dynamodb'
const DocumentClient = new DynamoDB.DocumentClient({
// Specify your client options as usual
convertEmptyValue: false
})
// Instantiate a table
const MyTable = new Table({
// Specify table name (used by DynamoDB)
name: 'my-table',
// Define partition and sort keys
partitionKey: 'pk',
sortKey: 'sk',
// Add the DocumentClient
DocumentClient
})
Create an Entity:
const Customer = new Entity({
// Specify entity name
name: 'Customer',
// Define attributes
attributes: {
id: { partitionKey: true }, // flag as partitionKey
sk: { hidden: true, sortKey: true }, // flag as sortKey and mark hidden
age: { type: 'number' }, // set the attribute type
name: { type: 'string', map: 'data' }, // map 'name' to table attribute 'data'
emailVerified: { type: 'boolean', required: true }, // specify attribute as required
co: { alias: 'company' }, // alias table attribute 'co' to 'company'
status: ['sk', 0], // composite key mapping
date_added: ['sk', 1] // composite key mapping
},
// Assign it to our table
table: MyTable
// In Typescript, the "as const" statement is needed for type inference
} as const)
Put an item:
// Create an item (using table attribute names or aliases)
const customer = {
id: 123,
age: 35,
name: 'Jane Smith',
emailVerified: true,
company: 'ACME',
status: 'active',
date_added: '2020-04-24'
}
// Use the 'put' method of Customer:
await Customer.put(customer)
The item will be saved to DynamoDB like this:
{
"pk": 123,
"sk": "active#2020-04-24",
"age": 35,
"data": "Jane Smith",
"emailVerified": true,
"co": "ACME",
// Attributes auto-generated by DynamoDB-Toolbox
"_et": "customer", // Entity name (required for parsing)
"_ct": "2021-01-01T00:00:00.000Z", // Item creation date (optional)
"_md": "2021-01-01T00:00:00.000Z" // Item last modification date (optional)
}
You can then get the data:
// Specify primary key
const primaryKey = {
id: 123,
status: 'active',
date_added: '2020-04-24'
}
// Use the 'get' method of Customer
const response = await Customer.get(primaryKey)
Since v0.4, the method inputs, options and response types are inferred from the Entity definition:
await Customer.put({
id: 123,
// โ Sort key is required ("sk" or both "status" and "date_added")
age: 35,
name: ['Jane', 'Smith'], // โ name should be a string
emailVerified: undefined, // โ attribute is marked as required
company: 'ACME'
})
const { Item: customer } = await Customer.get({
id: 123,
status: 'active',
date_added: '2020-04-24' // โ
Valid primary key
})
type Customer = typeof customer
// ๐ Type is equal to:
type ExpectedCustomer =
| {
id: any
age?: number | undefined
name?: string | undefined
emailVerified: boolean
company?: any
status: any
date_added: any
entity: string
created: string
modified: string
}
| undefined
See Type Inference for more details.
There are several really good Object-Relational Mapping tools (ORMs) out there for DynamoDB. There's the Amazon DynamoDB DataMapper For JavaScript, @Awspilot's DynamoDB project, @baseprime's dynamodb package, and many more.
If you like working with ORMs, that's great, and you should definitely give these projects a look. But personally, I really dislike ORMs (especially ones for relational databases). I typically find them cumbersome and likely to generate terribly inefficient queries (you know who you are). So this project is not an ORM, or at least it's not trying to be. This library helps you generate the necessary parameters needed to interact with the DynamoDB API by giving you a consistent interface and handling all the heavy lifting when working with the DynamoDB API. For convenience, this library will call the DynamoDB API for you and automatically parse the results, but you're welcome to just let it generate all (or just some) of the parameters for you. Hopefully this library will make the vast majority of your DynamoDB interactions super simple, and maybe even a little bit fun! ๐
- Table Schemas and DynamoDB Typings: Define your Table and Entity data models using a simple JavaScript object structure, assign DynamoDB data types, and optionally set defaults.
- Magic UpdateExpressions: Writing complex
UpdateExpression
strings is a major pain, especially if the input data changes the underlying clauses or requires dynamic (or nested) attributes. This library handles everything from simpleSET
clauses, to complexlist
andset
manipulations, to defaulting values with smartly appliedif_not_exists()
to avoid overwriting data. - Bidirectional Mapping and Aliasing: When building a single table design, you can define multiple entities that map to the same table. Each entity can reuse fields (like
pk
andsk
) and map them to different aliases depending on the item type. Your data is automatically mapped correctly when reading and writing data. - Composite Key Generation and Field Mapping: Doing some fancy data modeling with composite keys? Like setting your
sortKey
to[country]#[region]#[state]#[county]#[city]#[neighborhood]
model hierarchies? DynamoDB Toolbox lets you map data to these composite keys which will both autogenerate the value and parse them into fields for you. - Type Coercion and Validation: Automatically coerce values to strings, numbers and booleans to ensure consistent data types in your DynamoDB tables. Validate
list
,map
, andset
types against your data. Oh yeah, andset
s are automatically handled for you. ๐ - Powerful Query Builder: Specify a
partitionKey
, and then easily configure your sortKey conditions, filters, and attribute projections to query your primary or secondary indexes. This library can even handle pagination with a simple.next()
method. - Simple Table Scans: Scan through your table or secondary indexes and add filters, projections, parallel scans and more. And don't forget the pagination support with
.next()
. - Filter and Condition Expression Builder: Build complex Filter and Condition expressions using a standardized
array
andobject
notation. No more appending strings! - Projection Builder: Specify which attributes and paths should be returned for each entity type, and automatically filter the results.
- Secondary Index Support: Map your secondary indexes (GSIs and LSIs) to your table, and dynamically link your entity attributes.
- Batch Operations: Full support for batch operations with a simpler interface to work with multiple entities and tables.
- Transactions: Full support for transaction with a simpler interface to work with multiple entities and tables.
- Default Value Dependency Graphs: Create dynamic attribute defaults by chaining other dynamic attribute defaults together.
- TypeScript Support: v0.4 of this library provides strong typing support AND type inference ๐. Inferred type can still overriden with Overlays. Some Utility Types are also exposed. Additional work is still required to support schema validation & typings.
-
- query(partitionKey [,options] [,parameters])
- scan([options] [,parameters])
- batchGet(items [,options] [,parameters])
- batchWrite(items [,options] [,parameters])
- transactGet(items [,options] [,parameters])
- transactWrite(items [,options] [,parameters])
- parse(entity, input [,include])
- get(entity, key [,options] [,parameters])
- delete(entity, key [,options] [,parameters])
- put(entity, item [,options] [,parameters])
- update(entity, key [,options] [,parameters])
One of the most important goals of this library is to be as unopinionated as possible, giving you the flexibility to bend it to your will and build amazing applications. But another important goal is developer efficiency and ease of use. In order to balance these two goals, some assumptions had to be made. These include the "default" behavior of the library (all of which, btw, can be disabled with a simple configuration change). If you are using v0.1, you'll notice a lot of changes.
autoExecute
andautoParse
are enabled by default. The original version of this library only handled limited "parameter generation", so it was necessary for you to pass the payloads to theDocumentClient
. The library now provides support for all API options for each supported method, so by default, it will make the DynamoDB API call and parse the results, saving you redundant code. If you'd rather it didn't do this, you can disable it.- It assumes a Single Table DynamoDB design. Watch the Rick Houlihan videos and read Alex DeBrie's book. The jury is no longer out on this: Single Table designs are what all the cool kids are doing. This library assumes that you will have multiple "Entities" associated with a single "Table", so this requires you to instantiate a
Table
and add at least oneEntity
to it. If you have multipleTable
s and just oneEntity
type perTable
, that's fine, it'll still make your life much easier. Also,batchGet
andbatchWrite
support multiple tables, so we've got you covered. - Entity Types are added to all items. Since this library assumes a Single Table design, it needs a way to reliably distinguish between Entity types. It does this by adding an "Entity Type" field to each item in your table. v0.1 used
__model
, but this has been changed to_et
(short for "Entity Type"). Don't like this? Well, you can either disable it completely (but the library won't be able to parse entities into their aliases for you), or change the attribute name to something more snappy. It is purposefully short to minimize table storage (because item storage size includes the attribute names). Also, by default, Entities will alias this field toentity
(but you can change that too). - Created and modified timestamps are enabled by default. I can't think of many instances where created and modified timestamps aren't used in database records, so the library now automatically adds
_ct
and_md
attributes when items areput
orupdate
d. Again, these are kept purposefully short. You can disable them, change them, or even implement them yourself if you really want. By default, Entities will alias these attributes tocreated
andmodified
(customizable, of course), and will automatically apply anif_not_exists()
on updates so that thecreated
date isn't overwritten. - Option names have been shortened using camelCase. Nothing against long and descriptive names, but typing
ReturnConsumedCapacity
over and over again just seems like extra work. For simplification purposes, all API request parameters have been shortened to things likecapacity
,consistent
andmetrics
. The documentation shows which parameter they map to, but they should be intuitive enough to guess. - All configurations and options are plain JavaScript
objects
. There are lots of JS libraries that use function chaining (liketable.query('some pk value').condition('some condition').limit(50)
). I really like this style for lots of use cases, but it just feels wrong to me when using DynamoDB. DynamoDB is the OG of cloud native databases. It's configured using IaC and its API is HTTP-based and uses structured JSON, so writing queries and other interactions using its native format just seems like the right thing to do. IMO, this makes your code more explicit and easier to reason about. Youroptions
could actually be stored as JSON and (unless you're using functions to define defaults on Entity attributes) your Table and Entity configurations could be too. - API responses match the DynamoDB API responses. Something else I felt strongly about was the response signature returned by the library's methods. The DynamoDB Toolbox is a tool to help you interact with the DynamoDB API, NOT a replacement for it. ORMs typically trade ease of use with a tremendous amount of lock-in. But at the end of the day, it's just generating queries (and probably bad ones at that). DynamoDB Toolbox provides a number of helpful features to make constructing your API calls easier and more consistent, but the exact payload is always available to you. You can rip out this library whenever you want and just use the raw payloads if you really wanted to. This brings us to the responses. Other than aliasing the
Items
andAttributes
returned from DynamoDB, the structure and format of the responses is the exact same (including any other meta data returned). This not only makes the library (kind of) future proof, but also allows you to reuse or repurpose any code or tools you've already written to deal with API responses. - Attributes with NULL values are removed (by default). This was a hard one. I actually ran a Twitter poll to see how people felt about this, and although the reactions were mixed, "Remove the attributes" came out on top. I can understand the use cases for
NULL
s, but since NoSQL database attribute names are part of the storage considerations, it seems more logical to simply check for the absence of an attribute, rather than aNULL
value. You may disagree with me, and that's cool. I've provided aremoveNullAttributes
table setting that allows you to disable this and saveNULL
attributes to your heart's content. I wouldn't, but the choice is yours.
Hopefully these all make sense and will make working with the library easier.
Tables represent one-to-one mappings to your DynamoDB tables. They contain information about your table's name, primary keys, indexes, and more. They are also used to organize and coordinate operations between entities. Tables support a number of methods that allow you to interact with your entities including performing queries, scans, batch gets and batch writes.
To define a new table, import it into your script:
import { Table } from 'dynamodb-toolbox'
const MyTable = new Table({
... // Table definition
})
Table
takes a single parameter of type object
that accepts the following properties:
Property | Type | Required | Description |
---|---|---|---|
name | string |
yes | The name of your DynamoDB table (this will be used as the TableName property) |
alias | string |
no | An optional alias to reference your table when using "batch" features |
partitionKey | string |
yes | The attribute name of your table's partitionKey |
sortKey | string |
no | The attribute name of your table's sortKey |
entityField | boolean or string |
no | Disables or overrides entity tracking field name (default: _et ) |
attributes | object |
no | Complex type that optionally specifies the name and type of each attributes (see below) |
indexes | object |
no | Complex type that optionally specifies the name keys of your secondary indexes (see below) |
autoExecute | boolean |
no | Enables automatic execution of the DocumentClient method (default: true ) |
autoParse | boolean |
no | Enables automatic parsing of returned data when autoExecute is true (default: true ) |
removeNullAttributes | boolean |
no | Removes null attributes instead of setting them to null (default: true ) |
DocumentClient | DocumentClient |
* | A valid instance of the AWS DocumentClient |
* A Table can be instantiated without a DocumentClient, but most methods require it before execution
The Table attributes
property is an object
that specifies the names and types of attributes associated with your DynamoDB table. This is an optional input that allows you to control attribute types. If an Entity
object contains an attribute with the same name, but a different type, an error will be thrown. Each key in the object represents the attribute name and the value represents its DynamoDB type.
const MyTable = new Table({
attributes: {
pk: 'string',
sk: 'number',
attr1: 'list',
attr2: 'map',
attr3: 'boolean'
// ...
}
})
Valid DynamoDB types are: string
, boolean
, number
, list
, map
, binary
, or set
.
The indexes
property is an object
that specifies the names and keys of the secondary indexes on your DynamoDB table. Each key represents the index name and its value must contain an object with a partitionKey
AND/OR a sortKey
. partitionKey
s and sortKey
s require a value of type string
that references an table attribute. If you use the same partitionKey
as the table's partitionKey
, or you only specify a sortKey
, the library will recognize them as Local Secondary Indexes (LSIs). Otherwise, they will be Global Secondary Indexes (GSIs).
const MyTable = new Table({
indexes: {
GSI1: { partitionKey: 'GSI1pk', sortKey: 'GSI1sk' },
GSI2: { partitionKey: 'test' },
LSI1: { partitionKey: 'pk', sortKey: 'other_sk' },
LSI2: { sortKey: 'data' }
// ...
}
})
NOTE: The index name must match the index name on your table as it will be used in queries and other operations. The index must include the table's entityField
attribute for automatic parsing of returned data.
An Entity represent a well-defined schema for a DynamoDB item. An Entity can represent things like a User, an Order, an Invoice Line Item, a Configuration Object, or whatever else you want. Each Entity
defined with the DynamoDB Toolbox must be attached to a Table
. An Entity
defines its own attributes, but can share these attributes with other entities on the same table (either explicitly or coincidentally). Entities must flag an attribute as a partitionKey
and if enabled on the table, a sortKey
as well.
Note that a Table
can have multiple Entities, but an Entity
can only have one Table
.
To define a new entity, import it into your script:
import { Entity } from 'dynamodb-toolbox'
const MyEntity = new Entity({
...entityDefinition
// In Typescript, the "as const" statement is needed for type inference
} as const)
Entity
takes a single parameter of type object
that accepts the following properties:
Property | Type | Required | Description |
---|---|---|---|
name | string |
yes | The name of your entity (must be unique to its associated Table ) |
timestamps | boolean |
no | Automatically add and manage created and modified attributes |
created | string |
no | Override default created attribute name (default: _ct ) |
modified | string |
no | Override default modified attribute name (default: _md ) |
createdAlias | string |
no | Override default created alias name (default: created ) |
modifiedAlias | string |
no | Override default modified alias name (default: modified ) |
typeAlias | string |
no | Override default entity type alias name (default: entity ) |
attributes | object |
yes | Complex type that specifies the schema for the entity (see below) |
autoExecute | boolean |
no | Enables automatic execution of the DocumentClient method (default: inherited from Table) |
autoParse | boolean |
no | Enables automatic parsing of returned data when autoExecute evaluates to true (default: inherited from Table) |
table | Table |
* | A valid Table instance |
* An Entity can be instantiated without a table
, but most methods require one before execution
The attributes
property is an object
that represents the attribute names, types, and other properties related to each attribute. Each key in the object represents the attribute name and the value represents its properties. The value can be a string
that represents the DynamoDB type, an object
that allows for additional configurations, or an array
that maps to composite keys.
Attributes can be defined using only a string
value that corresponds to a DynamoDB type.
const MyEntity = new Entity({
attributes: {
attr1: 'string',
attr2: 'number',
attr3: 'list',
attr4: 'map'
// ...
}
} as const)
Valid types are: string
, boolean
, number
, list
, map
, binary
, or set
.
For more control over an attribute's behavior, you can specify an object as the attribute's value. Some options are specific to certain types. The following properties and options are available, all of which are optional:
Property | Type | For Types | Description |
---|---|---|---|
type | String |
all | The DynamoDB type for this attribute. Valid values are string , boolean , number , list , map , binary , or set . Defaults to string . |
coerce | boolean |
string , boolean , number , list |
Coerce values to the specified type. Enabled by default on string , boolean , and number . If enabled on list types, the interpreter will try to split a string by commas. |
default | same as type or function |
all | Specifies a default value (if none provided) when using get , put , update or delete methods. This also supports functions for creating custom default. See more below. |
dependsOn | string or array of string s |
all | Creates a dependency graph for default values. For example, if the attribute uses a default value that requires another attribute's default value, this will ensure dependent attributes' default values are calculated first. |
onUpdate | boolean |
all | Forces default values to be passed on every update . |
save | boolean |
all | Specifies whether this attribute should be saved to the table. Defaults to true . |
hidden | boolean |
all | Hides attribute from returned JS object when auto-parsing is enabled or when using the parse method. |
required | boolean or "always" |
all | Specifies whether an attribute is required. A value of true requires the attribute for all put operations. A string value of "always" requires the attribute for put and update operations. |
alias | string |
all | Adds a bidirectional alias to the attribute. All input methods can use either the attribute name or the alias when passing in data. Auto-parsing and the parse method will map attributes to their alias. |
map | string |
all | The inverse of the alias option, allowing you to specify your alias as the key and map it to an attribute name. |
setType | string |
set |
Specifies the type for set attributes. Allowed values are string ,number ,binary |
delimiter | string |
composite keys | Specifies the delimiter to use if this attribute stores a composite key (see Using an array for composite keys) |
prefix | string |
string |
A prefix to be added to an attribute when saved to DynamoDB. This prefix will be removed when parsing the data. |
suffix | string |
string |
A suffix to be added to an attribute when saved to DynamoDB. This suffix will be removed when parsing the data. |
transform | function |
all | A function that transforms the input before sending to DynamoDB. This accepts two arguments, the value passed and an object containing the data from other attributes. |
partitionKey | boolean or string |
all | Flags an attribute as the 'partitionKey' for this Entity. If set to true , it will be mapped to the Table's partitionKey . If set to the name of an index defined on the Table, it will be mapped to the secondary index's partitionKey |
sortKey | boolean or string |
all | Flags an attribute as the 'sortKey' for this Entity. If set to true , it will be mapped to the Table's sortKey . If set to the name of an index defined on the Table, it will be mapped to the secondary index's sortKey |
NOTE: One attribute must be set as the partitionKey
. If the table defines a sortKey
, one attribute must be set as the sortKey
. Assignment of secondary indexes is optional. If an attribute is used across multiple indexes, an array
can be used to specify multiple values.
Example:
const MyEntity = new Entity({
attributes: {
user_id: { partitionKey: true },
sk: { type: 'number', hidden: true, sortKey: true },
data: { coerce: false, required: true, alias: 'name' },
departments: { type: 'set', setType: 'string', map: 'dept' }
// ...
}
} as const)
NOTE: The interface for composite keys may be changing in v0.5 to make it easier to customize and infer types.
Composite keys in DynamoDB are incredibly useful for creating hierarchies, one-to-many relationships, and other powerful querying capabilities (see here). The DynamoDB Toolbox lets you easily work with composite keys in a number of ways. In some cases, there is no need to store the data in the same record twice if you are already combining it into a single attribute. By using composite key mappings, you can store data together in a single field, but still be able to structure input data and parse the output into separate attributes.
The basic syntax is to specify an array
with the mapped attribute name as the first element, and the index in the composite key as the second element. For example:
const MyEntity = new Entity({
attributes: {
user_id: { partitionKey: true },
sk: { hidden: true, sortKey: true },
status: ['sk', 0],
date: ['sk', 1]
// ...
}
} as const)
This maps the status
and date
attributes to the sk
attribute. If a status
and date
are supplied, they will be combined into the sk
attribute as [status]#[date]
. When the data is retrieved, the parse
method will automatically split the sk
attribute and return the values with status
and date
keys. By default, the values of composite keys are stored as separate attributes, but that can be changed by adding in an option configuration as the third array element.
Passing in a configuration
Composite key mappings are string
s by default, but can be overridden by specifying either string
,number
, or boolean
as the third element in the array. Composite keys are automatically coerced into string
s, so only the aforementioned types are allowed. You can also pass in a configuration object
as the third element. This uses the same configuration properties as above. In addition to these properties, you can also specify a boolean
property of save
. This will write the value to the mapped composite key, but also add a separate attribute that stores the value.
const MyEntity = new Entity({
attributes: {
user_id: { partitionKey: true },
sk: { hidden: true, sortKey: true },
status: ['sk', 0, { type: 'boolean', save: false, default: true }],
date: ['sk', 1, { required: true }]
// ...
}
} as const)
In simple situations, defaults can be static values. However, for advanced use cases, you can specify an anonymous function to dynamically calculate the value. The function takes a single argument that contains an object of the inputed data (including aliases). Sadly, in TS, type inference cannot be used here as this would create a circular dependency.
This opens up a number of really powerful use cases:
Generate the current date and time:
const MyEntity = new Entity({
attributes: {
user_id: { partitionKey: true },
created: { default: () => new Date().toISOString() }
// ...
}
} as const)
Generate a custom composite key:
const MyEntity = new Entity({
attributes: {
user_id: { partitionKey: true },
sk: {
sortKey: true,
default: (data: { status: boolean; date_added: string }) =>
`sort-${data.status}|${data.date_added}`
},
status: 'boolean',
date_added: 'string'
// ...
}
} as const)
Create conditional defaults:
const MyEntity = new Entity({
attributes: {
user_id: { partitionKey: true },
sk: {
sortKey: true,
default: (data: { status: boolean; date_added: string }) => {
if (data.status && data.date_added) {
return data.date_added
} else {
return null // field will not be defaulted
}
}
},
status: 'boolean',
date_added: 'string'
// ...
}
} as const)
The DocumentClient
property allows you to get reference to the table's assigned DocumentClient
, or to add/update the table's DocumentClient
. When setting this property, it must be a valid instance of the AWS DocumentClient.
The entities
property is used to add entities to the table. When adding entities, property accepts either an array
of Entity
instances, or a single Entity
instance. This will add the entities to the table and create a table property with the same name as your entities name
. For example, if an entity with the name User
is assigned: MyTable.entities = User
, then the Entity and its properties and methods will be accessible via MyTable.User
.
The entities
property will retrieve an array
of string
s containing all entity names attached to the table.
This property will retrieve a boolean
indicating the current autoExecute
setting on the table. You can change this setting by supplying a boolean
value.
This property will retrieve a boolean
indicating the current autoParse
setting on the table. You can change this setting by supplying a boolean
value.
The Query operation finds items based on primary key values. You can query any table or secondary index that has a composite primary key (a partition key and a sort key).
The query
method is a wrapper for the DynamoDB Query API. The DynamoDB Toolbox query
method supports all Query API operations. The query
method returns a Promise
and you must use await
or .then()
to retrieve the results. An alternative, synchronous method named queryParams
can be used, but will only retrieve the generated parameters.
The query()
method accepts three arguments. The first argument is used to specify the partitionKey
you wish to query against (KeyConditionExpression). The value must match the type of your table's partition key.
The second argument is an options
object that specifies the details of your query. The following options are all optional (corresponding Query API references in parentheses):
Option | Type | Description |
---|---|---|
index | string |
Name of secondary index to query. If not specified, the query executes on the primary index. The index must include the table's entityField attribute for automatic parsing of returned data. (IndexName) |
limit | number |
The maximum number of items to retrieve per query. (Limit) |
reverse | boolean |
Reverse the order or returned items. (ScanIndexForward) |
consistent | boolean |
Enable a consistent read of the items (ConsistentRead) |
capacity | string |
Return the amount of consumed capacity. One of either none , total , or indexes (ReturnConsumedCapacity) |
select | string |
The attributes to be returned in the result. One of either all_attributes , all_projected_attributes , specific_attributes , or count (Select) |
eq | same as sortKey |
Specifies sortKey condition to be equal to supplied value. (KeyConditionExpression) |
lt | same as sortKey |
Specifies sortKey condition to be less than supplied value. (KeyConditionExpression) |
lte | same as sortKey |
Specifies sortKey condition to be less than or equal to supplied value. (KeyConditionExpression) |
gt | same as sortKey |
Specifies sortKey condition to be greater than supplied value. (KeyConditionExpression) |
gte | same as sortKey |
Specifies sortKey condition to be greater than or equal to supplied value. (KeyConditionExpression) |
between | array |
Specifies sortKey condition to be between the supplied values. Array should have two values matching the sortKey type. (KeyConditionExpression) |
beginsWith | same as sortKey |
Specifies sortKey condition to begin with the supplied values. (KeyConditionExpression) |
filters | array or object |
A complex object or array of objects that specifies the query's filter condition. See Filters and Conditions. (FilterExpression) |
attributes | array or object |
An array or array of complex objects that specify which attributes should be returned. See Projection Expression below (ProjectionExpression) |
startKey | object |
An object that contains the partitionKey and sortKey of the first item that this operation will evaluate (if you're querying a secondary index, the keys for the primary index will also need to be included in the object - see LastEvaluatedKey result for details). (ExclusiveStartKey) |
entity | string |
The name of a table Entity to evaluate filters and attributes against. |
execute | boolean |
Enables/disables automatic execution of the DocumentClient method (default: inherited from Entity) |
parse | boolean |
Enables/disables automatic parsing of returned data when autoExecute evaluates to true (default: inherited from Entity) |
If you prefer to specify your own parameters, the optional third argument allows you to add custom parameters. See Adding custom parameters and clauses for more information.
const result = await MyTable.query(
'user#12345', // partition key
{
limit: 50, // limit to 50 items
beginsWith: 'order#', // select items where sort key begins with value
reverse: true, // return items in descending order (newest first)
capacity: 'indexes', // return the total capacity consumed by the indexes
filters: { attr: 'total', gt: 100 }, // only show orders above $100
index: 'GSI1' // query the GSI1 secondary index
}
)
The data is returned with the same response syntax as the DynamoDB Query API. In TS, type inference is not applied. If autoExecute
and autoParse
are enabled, any Items
data returned will be parsed into its corresponding Entity's aliases. Otherwise, the DocumentClient will return the unmarshalled data. If the response is parsed by the library, a .next()
method will be available on the returned object. Calling this function will call the query
method again using the same parameters and passing the LastEvaluatedKey
in as the ExclusiveStartKey
. This is a convenience method for paginating the results.
The Scan operation returns one or more items and item attributes by accessing every item in a table or a secondary index.
The scan
method is a wrapper for the DynamoDB Scan API. The DynamoDB Toolbox scan
method supports all Scan API operations. The scan
method returns a Promise
and you must use await
or .then()
to retrieve the results. An alternative, synchronous method named scanParams
can be used, but will only retrieve the generated parameters.
The scan()
method accepts two arguments. The first argument is an options
object that specifies the details of your scan. The following options are all optional (corresponding Scan API references in parentheses):
Option | Type | Description |
---|---|---|
index | string |
Name of secondary index to scan. If not specified, the query executes on the primary index. The index must include the table's entityField attribute for automatic parsing of returned data. (IndexName) |
limit | number |
The maximum number of items to retrieve per scan. (Limit) |
consistent | boolean |
Enable a consistent read of the items (ConsistentRead) |
capacity | string |
Return the amount of consumed capacity. One of either none , total , or indexes (ReturnConsumedCapacity) |
select | string |
The attributes to be returned in the result. One of either all_attributes , all_projected_attributes , specific_attributes , or count (Select) |
filters | array or object |
A complex object or array of objects that specifies the scan's filter condition. See Filters and Conditions. (FilterExpression) |
attributes | array or object |
An array or array of complex objects that specify which attributes should be returned. See Projection Expression below (ProjectionExpression) |
startKey | object |
An object that contains the partitionKey and sortKey of the first item that this operation will evaluate. (ExclusiveStartKey) |
segments | number |
For a parallel scan request, segments represents the total number of segments into which the scan operation will be divided. (TotalSegments) |
segment | number |
For a parallel scan request, segment identifies an individual segment to be scanned by an application worker. (Segment) |
entity | string |
The name of a table Entity to evaluate filters and attributes against. |
execute | boolean |
Enables/disables automatic execution of the DocumentClient method (default: inherited from Entity) |
parse | boolean |
Enables/disables automatic parsing of returned data when autoExecute evaluates to true (default: inherited from Entity) |
If you prefer to specify your own parameters, the optional second argument allows you to add custom parameters. See Adding custom parameters and clauses for more information.
const result = await MyTable.scan({
limit: 100, // limit to 50 items
capacity: 'indexes', // return the total capacity consumed by the indexes
filters: { attr: 'total', between: [100, 500] }, // only return orders between $100 and $500
index: 'GSI1' // scan the GSI1 secondary index
})
The data is returned with the same response syntax as the DynamoDB Scan API. In TS, type inference is not applied. If autoExecute
and autoParse
are enabled, any Items
data returned will be parsed into its corresponding Entity's aliases. Otherwise, the DocumentClient will return the unmarshalled data. If the response is parsed by the library, a .next()
method will be available on the returned object. Calling this function will call the scan
method again using the same parameters and passing the LastEvaluatedKey
in as the ExclusiveStartKey
. This is a convenience method for paginating the results.
The BatchGetItem operation returns the attributes of one or more items from one or more tables. You identify requested items by primary key.
The batchGet
method is a wrapper for the DynamoDB BatchGetItem API. The DynamoDB Toolbox batchGet
method supports all BatchGetItem API operations. The batchGet
method returns a Promise
and you must use await
or .then()
to retrieve the results. An alternative, synchronous method named batchGetParams
can be used, but will only retrieve the generated parameters.
The batchGet
method accepts three arguments. The first is an array
of item keys to get. The DynamoDB Toolbox provides the getBatch
method on your entities to help you generate the proper key configuration. You can specify different entity types as well as entities from different tables, and this library will handle the proper payload construction.
The optional second argument accepts an options
object. The following options are all optional (corresponding BatchGetItem API references in parentheses):
Option | Type | Description |
---|---|---|
consistent | boolean or object (see below) |
Enable a consistent read of the items (ConsistentRead) |
capacity | string |
Return the amount of consumed capacity. One of either none , total , or indexes (ReturnConsumedCapacity) |
attributes | array or object (see below) |
An array or array of complex objects that specify which attributes should be returned. See Projection Expression below (ProjectionExpression) |
execute | boolean |
Enables/disables automatic execution of the DocumentClient method (default: inherited from Entity) |
parse | boolean |
Enables/disables automatic parsing of returned data when autoExecute evaluates to true (default: inherited from Entity) |
The library is built for making working with single table designs easier, but it is possible that you may need to retrieve data from multiple tables within the same batch get. If your items
contain references to multiple tables, the consistent
option will accept objects that use either the table name
or alias
as the key, and the setting as the value. For example, to specify different consistent
settings on two tables, you would use something like following:
const results = await MyTable.batchGet(
// ... ,
{
consistent: {
'my-table-name': true,
'my-other-table-name': false
}
// ...
}
)
Setting either value without the object
structure will set the option for all referenced tables. If you are referencing multiple tables and using the attributes
option, then you must use the same object
method to specify the table name
or alias
. The value should follow the standard Projection Expression formatting.
const results = await MyTable.batchGet(
[
MyTable.User.getBatch({ family: 'Brady', name: 'Mike' }),
MyTable.User.getBatch({ family: 'Brady', name: 'Carol' }),
MyTable.Pet.getBatch({ family: 'Brady', name: 'Tiger' })
],
{
capacity: 'total',
attributes: [
'name', 'family',
{ User: ['dob', 'age'] },
{ Pet: ['petType','lastVetCheck'] }
]
}
}
)
If you prefer to specify your own parameters, the optional third argument allows you to add custom parameters. See Adding custom parameters and clauses for more information.
The data is returned with the same response syntax as the DynamoDB BatchGetItem API. In TS, type inference is not applied. If autoExecute
and autoParse
are enabled, any Responses
data returned will be parsed into its corresponding Entity's aliases. Otherwise, the DocumentClient will return the unmarshalled data. If the response is parsed by the library, a .next()
method will be available on the returned object. Calling this function will call the batchGet
method again using the same options and passing any UnprocessedKeys
in as the RequestItems
. This is a convenience method for retrying unprocessed keys.
The BatchWriteItem operation puts or deletes multiple items in one or more tables. A single call to BatchWriteItem can write up to 16 MB of data, which can comprise as many as 25 put or delete requests.
The batchWrite
method is a wrapper for the DynamoDB BatchWriteItem API. The DynamoDB Toolbox batchWrite
method supports all BatchWriteItem API operations. The batchWrite
method returns a Promise
and you must use await
or .then()
to retrieve the results. An alternative, synchronous method named batchWriteParams
can be used, but will only retrieve the generated parameters.
The batchWrite
method accepts three arguments. The first is an array
of item keys to either put
or delete
. The DynamoDB Toolbox provides a putBatch
and deleteBatch
method on your entities to help you generate the proper key configuration for each item. You can specify different entity types as well as entities from different tables, and this library will handle the proper payload construction.
The optional second argument accepts an options
object. The following options are all optional (corresponding BatchWriteItem API references in parentheses):
Option | Type | Description |
---|---|---|
capacity | string or object (see below) |
Return the amount of consumed capacity. One of either none , total , or indexes (ReturnConsumedCapacity) |
metrics | string |
Return item collection metrics. If set to size , the response includes statistics about item collections, if any, that were modified during the operation are returned in the response. One of either none or size (ReturnItemCollectionMetrics) |
execute | boolean |
Enables/disables automatic execution of the DocumentClient method (default: inherited from Entity) |
parse | boolean |
Enables/disables automatic parsing of returned data when autoExecute evaluates to true (default: inherited from Entity) |
NOTE: The BatchWriteItem
does not support conditions or return deleted items. "BatchWriteItem does not behave in the same way as individual PutItem and DeleteItem calls would. For example, you cannot specify conditions on individual put and delete requests, and BatchWriteItem does not return deleted items in the response." ~ DynamoDB BatchWriteItem API
const result = await Default.batchWrite(
[
MyTable.User.putBatch({ family: 'Brady', name: 'Carol', age: 40, roles: ['mother', 'wife'] }),
MyTable.User.putBatch({ family: 'Brady', name: 'Mike', age: 42, roles: ['father', 'husband'] }),
MyTable.Pet.deleteBatch({ family: 'Brady', name: 'Tiger' })
],
{
capacity: 'total',
metrics: 'size'
}
)
If you prefer to specify your own parameters, the optional third argument allows you to add custom parameters. See Adding custom parameters and clauses for more information.
The data is returned with the same response syntax as the DynamoDB BatchWriteItem API. If autoExecute
and autoParse
are enabled, a .next()
method will be available on the returned object. Calling this function will call the batchWrite
method again using the same options and passing any UnprocessedItems
in as the RequestItems
. This is a convenience method for retrying unprocessed keys.
TransactGetItems is a synchronous operation that atomically retrieves multiple items from one or more tables (but not from indexes) in a single account and Region.
The transactGet
method is a wrapper for the DynamoDB TransactGetItems API. The DynamoDB Toolbox transactGet
method supports all TransactGetItem API operations. The transactGet
method returns a Promise
and you must use await
or .then()
to retrieve the results. An alternative, synchronous method named transactGetParams
can be used, but will only retrieve the generated parameters.
The transacthGet
method accepts three arguments. The first is an array
of item keys to get. The DynamoDB Toolbox provides the getTransaction
method on your entities to help you generate the proper key configuration. You can specify different entity types as well as entities from different tables, and this library will handle the proper payload construction.
The optional second argument accepts an options
object. The following options are all optional (corresponding TransactGetItems API references in parentheses):
Option | Type | Description |
---|---|---|
capacity | string |
Return the amount of consumed capacity. One of either none , total , or indexes (ReturnConsumedCapacity) |
execute | boolean |
Enables/disables automatic execution of the DocumentClient method (default: inherited from Table) |
parse | boolean |
Enables/disables automatic parsing of returned data when autoExecute evaluates to true (default: inherited from Table) |
Transaction items are atomic, so each Get
contains the table name and key necessary to retrieve the item. The library will automatically handle adding the necessary information and will parse each entity automatically for you.
const results = await MyTable.transactGet(
[
User.getTransaction({ family: 'Brady', name: 'Mike' }),
User.getTransaction({ family: 'Brady', name: 'Carol' }),
Pet.getTransaction({ family: 'Brady', name: 'Tiger' })
],
{ capacity: 'total' }
)
If you prefer to specify your own parameters, the optional third argument allows you to add custom parameters. See Adding custom parameters and clauses for more information.
The data is returned with the same response syntax as the DynamoDB TransactGetItems API. In TS, type inference is not applied. If autoExecute
and autoParse
are enabled, any Responses
data returned will be parsed into its corresponding Entity's aliases. Otherwise, the DocumentClient will return the unmarshalled data.
TransactWriteItems is a synchronous write operation that groups up to 25 action requests. The actions are completed atomically so that either all of them succeed, or all of them fail.
The transactWrite
method is a wrapper for the DynamoDB TransactWriteItems API. The DynamoDB Toolbox transactWrite
method supports all TransactWriteItems API operations. The transactWrite
method returns a Promise
and you must use await
or .then()
to retrieve the results. An alternative, synchronous method named transactWriteParams
can be used, but will only retrieve the generated parameters.
The transactWrite
method accepts three arguments. The first is an array
of item keys to either put
, delete
, update
or conditionCheck
. The DynamoDB Toolbox provides putTransaction
,deleteTransaction
, updateTransaction
, and conditionCheck
methods on your entities to help you generate the proper configuration for each item. You can specify different entity types as well as entities from different tables, and this library will handle the proper payload construction.
The optional second argument accepts an options
object. The following options are all optional (corresponding TransactWriteItems API references in parentheses):
Option | Type | Description |
---|---|---|
capacity | string |
Return the amount of consumed capacity. One of either none , total , or indexes (ReturnConsumedCapacity) |
metrics | string |
Return item collection metrics. If set to size , the response includes statistics about item collections, if any, that were modified during the operation are returned in the response. One of either none or size (ReturnItemCollectionMetrics) |
token | string |
Optional token to make the call idempotent, meaning that multiple identical calls have the same effect as one single call. (ClientRequestToken) |
execute | boolean |
Enables/disables automatic execution of the DocumentClient method (default: inherited from Entity) |
parse | boolean |
Enables/disables automatic parsing of returned data when autoExecute evaluates to true (default: inherited from Entity) |
const result = await Default.transactWrite(
[
Pet.conditionCheck({ family: 'Brady', name: 'Tiger' }, { conditions: { attr: 'alive', eq: false } },
Pet.deleteTransaction({ family: 'Brady', name: 'Tiger' }),
User.putTransaction({ family: 'Brady', name: 'Carol', age: 40, roles: ['mother','wife'] }),
User.putTransaction({ family: 'Brady', name: 'Mike', age: 42, roles: ['father','husband'] })
],{
capacity: 'total',
metrics: 'size',
}
)
If you prefer to specify your own parameters, the optional third argument allows you to add custom parameters. See Adding custom parameters and clauses for more information.
The data is returned with the same response syntax as the DynamoDB TransactWriteItems API.
Executes the parse
method of the supplied entity
. The entity
must be a string
that references the name of an Entity associated with the table. See the Entity parse
method for additional parameters and behavior. In TS, type inference is not applied.
Executes the get
method of the supplied entity
. The entity
must be a string
that references the name of an Entity associated with the table. See the Entity get
method for additional parameters and behavior. In TS, type inference is not applied.
Executes the delete
method of the supplied entity
. The entity
must be a string
that references the name of an Entity associated with the table. See the Entity delete
method for additional parameters and behavior.
Executes the put
method of the supplied entity
. The entity
must be a string
that references the name of an Entity associated with the table. See the Entity put
method for additional parameters and behavior.
Executes the update
method of the supplied entity
. The entity
must be a string
that references the name of an Entity associated with the table. See the Entity update
method for additional parameters and behavior.
Retrieves a reference to the Table instance that the Entity is attached to. You can use this property to add the Entity to a Table by assigning it a valid Table instance. Note that you cannot change a table once it has been assigned.
The DocumentClient
property retrieves a reference to the table's assigned DocumentClient
. This value cannot be updated by the Entity.
This property will retrieve a boolean
indicating the current autoExecute
setting on the entity. If no value is set, it will return the inherited value from the attached table. You can change this setting for the current entity by supplying a boolean
value.
This property will retrieve a boolean
indicating the current autoParse
setting on the entity. If no value is set, it will return the inherited value from the attached table. You can change this setting for the current entity by supplying a boolean
value.
Returns the Entity's assigned partitionKey
.
Returns the Entity's assigned sortKey
.
Returns the Table's attribute name for the suppled attribute
. The attribute
must be a string
and can be either a valid attribute name or alias.
Parses attributes returned from a DynamoDB action and unmarshalls them into entity aliases. The input
argument accepts an object
with attributes as keys, an array
of objects
with attributes as keys, or an object
with either an Item
or Items
property. This method will return a result of the same type of input
. For example, if you supply an array
of objects, an array
will be returned. If you supply an object with an Item
property, an object
will be returned.
You can also pass in an array
of strings as the second argument. The unmarshalling will only return the attributes (or aliases) specified in this include
array.
If auto execute and auto parsing are enabled, data returned from a DynamoDB action will automatically be parsed.
The GetItem operation returns a set of attributes for the item with the given primary key.
The get
method is a wrapper for the DynamoDB GetItem API. The DynamoDB Toolbox get
method supports all GetItem API operations. The get
method returns a Promise
and you must use await
or .then()
to retrieve the results. An alternative, synchronous method named getParams
can be used, but will only retrieve the generated parameters.
The get
method accepts three arguments. The first argument accepts an object
that is used to specify the primary key of the item you wish to "get" (Key). The object
must contain keys for the attributes that represent your partitionKey
and sortKey
(if a compound key) with their values as the key values. For example, if user_id
represents your partitionKey
, and status
represents your sortKey
, to retrieve user_id "123" with a status of "active", you would specify { user_id: 123, status: 'active' }
as your key
.
The optional second argument accepts an options
object. The following options are all optional (corresponding GetItem API references in parentheses):
Option | Type | Description |
---|---|---|
consistent | boolean |
Enable a consistent read of the items (ConsistentRead) |
capacity | string |
Return the amount of consumed capacity. One of either none , total , or indexes (ReturnConsumedCapacity) |
attributes | array or object |
An array or array of complex objects that specify which attributes should be returned. See Projection Expression below (ProjectionExpression) |
execute | boolean |
Enables/disables automatic execution of the DocumentClient method (default: inherited from Entity) |
parse | boolean |
Enables/disables automatic parsing of returned data when autoExecute evaluates to true (default: inherited from Entity) |
If you prefer to specify your own parameters, the optional third argument allows you to add custom parameters. See Adding custom parameters and clauses for more information.
const { Item } = await MyEntity.get({
pk: 123,
sk: 'sort-key'
})
In TS, the primary key, attributes
option and response types are dynamically inferred. See Type Inference for more details.
Deletes a single item in a table by primary key.
The delete
method is a wrapper for the DynamoDB DeleteItem API. The DynamoDB Toolbox delete
method supports all DeleteItem API operations. The delete
method returns a Promise
and you must use await
or .then()
to retrieve the results. An alternative, synchronous method named deleteParams
can be used, but will only retrieve the generated parameters.
The delete
method accepts three arguments. The first argument accepts an object
that is used to specify the primary key of the item you wish to "delete" (Key). For example: { user_id: 123, status: 'active' }
The optional second argument accepts an options
object. The following options are all optional (corresponding DeleteItem API references in parentheses):
Option | Type | Description |
---|---|---|
conditions | array or object |
A complex object or array of objects that specifies the conditions that must be met to delete the item. See Filters and Conditions. (ConditionExpression) |
capacity | string |
Return the amount of consumed capacity. One of either none , total , or indexes (ReturnConsumedCapacity) |
metrics | string |
Return item collection metrics. If set to size , the response includes statistics about item collections, if any, that were modified during the operation are returned in the response. One of either none or size (ReturnItemCollectionMetrics) |
returnValues | string |
Determins whether to return item attributes as they appeared before they were deleted. One of either none or all_old . (ReturnValues) |
execute | boolean |
Enables/disables automatic execution of the DocumentClient method (default: inherited from Entity) |
parse | boolean |
Enables/disables automatic parsing of returned data when autoExecute evaluates to true (default: inherited from Entity) |
If you prefer to specify your own parameters, the optional third argument allows you to add custom parameters. See Adding custom parameters and clauses for more information.
await MyEntity.delete(
{ pk: 123, sk: 'sort-key' },
{
conditions: { attr: 'date_modified' lt: '2020-01-01' },
returnValues: 'all_old'
}
)
In TS, the primary key, conditions
option and response types are dynamically inferred. See Type Inference for more details.
Creates a new item, or replaces an old item with a new item. If an item that has the same primary key as the new item already exists in the specified table, the new item completely replaces the existing item.
The put
method is a wrapper for the DynamoDB PutItem API. The DynamoDB Toolbox put
method supports all PutItem API operations. The put
method returns a Promise
and you must use await
or .then()
to retrieve the results. An alternative, synchronous method named putParams
can be used, but will only retrieve the generated parameters.
The put
method accepts three arguments. The first argument accepts an object
that represents the item to add to the DynamoDB table. The item can use attribute names or aliases and will convert the object into the appropriate shape defined by your Entity.
The optional second argument accepts an options
object. The following options are all optional (corresponding PutItem API references in parentheses):
Option | Type | Description |
---|---|---|
conditions | array or object |
A complex object or array of objects that specifies the conditions that must be met to put the item. See Filters and Conditions. (ConditionExpression) |
capacity | string |
Return the amount of consumed capacity. One of either none , total , or indexes (ReturnConsumedCapacity) |
metrics | string |
Return item collection metrics. If set to size , the response includes statistics about item collections, if any, that were modified during the operation are returned in the response. One of either none or size (ReturnItemCollectionMetrics) |
returnValues | string |
Determins whether to return item attributes as they appeared before a new item was added. One of either none or all_old . (ReturnValues) |
execute | boolean |
Enables/disables automatic execution of the DocumentClient method (default: inherited from Entity) |
parse | boolean |
Enables/disables automatic parsing of returned data when autoExecute evaluates to true (default: inherited from Entity) |
If you prefer to specify your own parameters, the optional third argument allows you to add custom parameters. See Adding custom parameters and clauses for more information.
await MyEntity.put({
id: 123,
name: 'Jane Smith',
company: 'ACME',
age: 35,
status: 'active',
date_added: '2020-04-24'
})
In TS, the input item, conditions
option and response types are dynamically inferred. See Type Inference for more details.
Edits an existing item's attributes, or adds a new item to the table if it does not already exist. You can put, delete, or add attribute values.
The update
method is a wrapper for the DynamoDB UpdateItem API. The DynamoDB Toolbox update
method supports all UpdateItem API operations. The update
method returns a Promise
and you must use await
or .then()
to retrieve the results. An alternative, synchronous method named updateParams
can be used, but will only retrieve the generated parameters.
The update
method accepts three arguments. The first argument accepts an object
that represents the item key and attributes to be updated. The item can use attribute names or aliases and will convert the object into the appropriate shape defined by your Entity.
The optional second argument accepts an options
object. The following options are all optional (corresponding UpdateItem API references in parentheses):
Option | Type | Description |
---|---|---|
conditions | array or object |
A complex object or array of objects that specifies the conditions that must be met to update the item. See Filters and Conditions. (ConditionExpression) |
capacity | string |
Return the amount of consumed capacity. One of either none , total , or indexes (ReturnConsumedCapacity) |
metrics | string |
Return item collection metrics. If set to size , the response includes statistics about item collections, if any, that were modified during the operation are returned in the response. One of either none or size (ReturnItemCollectionMetrics) |
returnValues | string |
Determins whether to return item attributes as they appeared before or after the item was updated. One of either NONE , ALL_OLD , UPDATED_OLD , ALL_NEW , UPDATED_NEW . (ReturnValues) |
execute | boolean |
Enables/disables automatic execution of the DocumentClient method (default: inherited from Entity) |
parse | boolean |
Enables/disables automatic parsing of returned data when autoExecute evaluates to true (default: inherited from Entity) |
If you prefer to specify your own parameters, the optional third argument allows you to add custom parameters and clauses. See Adding custom parameters and clauses for more information.
But wait, there's more! The UpdateExpression
lets you do all kinds of crazy things like REMOVE
attributes, ADD
values to numbers and sets, and manipulate arrays. The DynamoDB Toolbox has simple ways to deal with all these different operations by properly formatting your input data.
To update an attribute, include the key and any fields that you want to update.
await MyEntity.update({
pk: 123,
sk: 'abc',
status: 'inactive'
})
In TS, the input item, conditions
option and response types are dynamically inferred. See Type Inference for more details.
To remove attributes, add a $remove
key to your item and provide an array of attributes or aliases to remove.
await MyEntity.update({
// ...
$remove: ['roles', 'age']
})
DynamoDB lets us add (or subtract) numeric values from an attribute in the table. If no value exists, it simply puts the value. Adding with the DynamoDB Toolbox is just a matter of supplying an object
with an $add
key on the number fields you want to update.
await MyEntity.update({
// ...
level: { $add: 2 } // add 2 to level
})
Sets are similar to lists, but they enforce unique values of the same type. To add new values to a set, use an object
with an $add
key and an array of values.
await MyEntity.update({
// ...
roles: { $add: ['author', 'support'] }
})
To delete values from a set
, use an object
with a $delete
key and an array of values to delete.
await MyEntity.update({
// ...
roles: { $delete: ['admin'] }
})
To append values to a list
, use an object
with an $append
key and an array of values to append.
await MyEntity.update({
// ...
sessions: { $append: [{ date: '2020-04-24', duration: 101 }] }
})
Alternatively, you can use the $prepend
key and it will add the values to the beginning of the list.
To remove values from a list
, use an object
with a $remove
key and an array of indexes to remove. Lists are indexed starting at 0
, so the update below would remove the second, fifth, and sixth item in the array.
await MyEntity.update({
// ...
sessions: { $remove: [1, 4, 5] }
})
To update values in a list
, specify an object
with array indexes as the keys and the update data as the values. Lists are indexed starting at 0
, so the update below would update the second and fourth items in the array.
await MyEntity.update({
// ...
sessions: {
1: 'some new value for the second item',
3: 'new value for the fourth value'
}
})
Maps can be complex, deeply nested JavaScript objects with a variety of data types. The DynamoDB Toolbox doesn't support schemas for map
s (yet), but you can still manipulate them by wrapping your updates in a $set
parameter and using dot notation and array index notation to target fields.
await MyEntity.update({
// ...
metadata: {
$set: {
title: 'Developer', // update metadata.title
'contact.name': 'Jane Smith', // update metadata.contact.name
'contact.addresses[0]': '123 Main Street' // update the first array item in metadata.contact.addresses
}
}
})
We can also use our handy $add
, $append
, $prepend
, and $remove
properties to manipulate nested values.
await MyEntity.update({
// ...
metadata: {
$set: {
vacation_days: { $add: -2 },
'contact.addresses': { $append: ['99 South Street'] },
'contact.phone': { $remove: [1, 3] }
}
}
})
Executes the query
method on the parent Table. This method accepts the same parameters as the Table query
method and automatically sets the entity
option to the current entity. Due to the nature of DynamoDB queries, this method does not guarantee that only items of the current entity type will be returned.
In TS, the attributes
option and response types are dynamically inferred. See Type Inference for more details.
Executes the scan
method on the parent Table. This method accepts the same parameters as the Table scan
method and automatically sets the entity
option to the current entity. Due to the nature of DynamoDB scans, this method does not guarantee that only items of the current entity type will be returned.
In TS, the attributes
option and response types are dynamically inferred. See Type Inference for more details.
DynamoDB supports Filter and Condition expressions. Filter Expressions are used to limit data returned by query
and scan
operations. Condition Expressions are used for data manipulation operations (put
, update
, delete
and batchWrite
), allowing you to specify a condition to determine which items should be modified.
The DynamoDB Toolbox provides an Expression Builder that allows you to generate complex filters and conditions based on your Entity definitions. Any method that requires filters
or conditions
accepts an array
of conditions, or a single condition. Condition objects support the following properties:
Properties | Type | Description |
---|---|---|
attr | string |
Specifies the attribute to filter on. If an entity property is provided (or inherited from the calling operation), aliases can be used. Either attr or size must be provided. |
size | string |
Specifies which attribute's calculated size to filter on (see Operators and Functions for more information). If an entity property is provided (or inherited from the calling operation), aliases can be used. Either attr or size must be provided. |
eq | * | Specifies value to equal attribute or size of attribute. |
ne | * | Specifies value to not equal attribute or size of attribute. |
lt | * | Specifies value for attribute or size to be less than. |
lte | * | Specifies value for attribute or size to be less than or equal to. |
gt | * | Specifies value for attribute or size to be greater than. |
gte | * | Specifies value for attribute or size to be greater than or equal to. |
between | array |
Specifies values for attribute or size to be between. E.g. [18,49] . |
beginsWith | * | Specifies value for the attribute to begin with |
in | array |
Specifies and array of values that the attribute or size must match one value. |
contains | string |
Specifies value that must be contained within a string or Set. (see Operators and Functions for more information) |
exists | boolean |
Checks whether or not the attribute exists for an item. A value of true uses the attribute_exists() function and a value of false uses the attribute_not_exists() function (see Operators and Functions for more information) |
type | string |
A value that compares the attribute's type. Value must be one of S ,SS , N , NS , B , BS , BOOL , NULL , L , or M (see Operators and Functions for more information) |
or | boolean |
Changes the logical evaluation to OR (by default it's AND ) |
negate | boolean |
Adds NOT to the condition. |
entity | string |
The entity this attribute applies to. If supplied (or inherited from the calling operation), attr and size properties can use the entity's aliases to reference attributes. |
* Comparison values should equal the type of the attribute you are comparing against. If you are using the size
property, the value should be a number
.
In order to create complex filters and conditions, the DynamoDB Toolbox allows you to nest and combine filters by using nested array
s. Array brackets ([
and ]
) act as parentheses when constructing your condition. Using or
in the first condition within an array will change the logical evaluation for group of conditions.
Condition where age
is between 18 and 54 AND region
equals "US":
MyTable.query(
// ...,
{
filters: [
{ attr: 'age', between: [18, 54] },
{ attr: 'region', eq: 'US' }
]
}
)
Condition where age
is between 18 and 54 AND region
equals "US" OR "EU":
MyTable.query(
// ...,
{
filters: [
{ attr: 'age', between: [18, 54] },
[
{ attr: 'region', eq: 'US' },
{ or: true, attr: 'region', eq: 'EU' }
]
]
}
)
Condition where age
is greater than 21 OR ((region
equals "US" AND interests
size is greater than 10) AND interests
contain nodejs
, dynamodb
, or serverless
):
MyTable.query(
// ...,
{
filters: [
{ attr: 'age', gt: 21 },
[
[
{ or: true, attr: 'region', eq: 'US' },
{ size: 'interests', gt: 10 }
],
[
{ attr: 'interests', contains: 'nodejs' },
{ or: true, attr: 'interests', contains: 'dynamodb' },
{ or: true, attr: 'interests', contains: 'serverless' }
]
]
]
}
)
DynamoDB supports Projection Expressions that allow you to selectively return attributes when using the get
, query
or scan
operations.
The DynamoDB Toolbox provides a Projection Builder that allows you to generate ProjectionExpression
s that automatically generates ExpressionAttributeNames
as placeholders to avoid reservered word collisions. The library allows you to work with both table attribute names and Entity aliases to specify projections.
Read operations that provide an attributes
property accept an array
of attribute names and/or objects that specify the Entity as the key with an array of attributes and aliases.
Retrieve the pk
,sk
,name
and created
attributes for all items:
MyTable.query(
// ...,
{ attributes: ['pk', 'sk', 'name', 'created'] }
)
Retrieve the user_id
,status
, and created
attributes for the User
entity:
MyTable.query(
// ...,
{ attributes: [{ User: ['user_id', 'status', 'created'] }] }
)
Retrieve the pk
, sk
, and type
attributes for all items, the user_id
for the User
entity, and the status
and created
attributes for the the Order
entity:
MyTable.query(
// ...
{
attributes: ['pk', 'sk', 'type', { User: ['user_id'] }, { Order: ['status', 'created'] }]
}
)
When using the get
method of an entity, the "entity" is assumed for the attributes. This lets you specify attributes and aliases without needing to use the object reference.
NOTE: When specifying entities in query
and scan
operations, it's possible that shared attributes will retrieve data for other matching entity types. However, the library attempts to return only the attributes specified for each entity when parsing the response.
This libary supports all API options for the available API methods, so it is unnecessary for you to provide additional parameters. However, if you would like to pass custom parameters, simply pass them in an object as the last parameter to any appropriate method.
const result = await MyEntity.update(
item, // the item to update
{ ..options... }, // method options
{ // your custom parameters
ReturnConsumedCapacity: 'TOTAL',
ReturnValues: 'ALL_NEW'
}
)
For the update
method, you can add additional statements to the clauses by specifying arrays as the SET
, ADD
, REMOVE
and DELETE
properties. You can also specify additional ExpressionAttributeNames
and ExpressionAttributeValues
with object values and the system will merge them in with the generated ones.
const results = await MyEntity.update(
item,
{},
{
SET: ['#somefield = :somevalue'],
ExpressionAttributeNames: { '#somefield': 'somefield' },
ExpressionAttributeValues: { ':somevalue': 123 }
}
)
Since the v0.4, most Entity methods types are inferred from Entity definition.
The following options are implemented:
- ๐
partitionKey
,sortKey
: They are used, along with array-based mapped attributes to infer the primary key type. - โก๏ธ
autoExecute
,execute
: If theexecute
option is set tofalse
(either in the Entity definition or the method options), the method responses are typed asDocumentClient.<METHOD>ItemInput
. - ๐ง
autoParse
,parse
: If theparse
option is set tofalse
(either in the Entity definition or the method options), the method responses are typed asDocumentClient.<METHOD>ItemOutput
. - โ๏ธ
typeAlias
,createdAlias
,modifiedAlias
: Aliases are used to compute the parsed responses types. They are also prevented from attribute definitions to avoid conflicts. - โฐ
timestamps
: If thetimestamps
option is set to false,createdAlias
andmodifiedAlias
are omitted from the parsed responses types. - ๐ฎ
required
: Attributes flagged asrequired
are required as needed input
andupdate
operations. They appear as always defined in parsed responses. Attempting to remove them, either with the$delete
shorthand or by setting them tonull
causes an error. - ๐
default
: Required attributes are not required input
andupdate
operations if they have adefault
value. They appear as always defined in parsed responses. - โ๏ธ
attributes
: Inget
andqueries
operations, theattributes
option filter the attributes of the parsed responses types. - โ๏ธ
conditions
: Input
,update
anddelete
operations, theconditions
attributes are correctly typed. - ๐จ
returnValues
: Input
,update
anddelete
operation, thereturnValues
option is interpreted to format the responses. - ๐
hidden
: Hidden attributes are omitted from the parsed responses types. - ๐
dependsOn
option: If thedefault
property of a key attribute is a function, you can use thedependsOn
attribute to enable typing the primary key through the depended-on attributes (i.e. those used in the function).
The following options are not yet implemented:
alias
attribute option- Table attributes!
- Secondary indexes names
coerce
option- Improved
list
andset
support ... And probably more! Feel free to open an issue if needed ๐ค
When type infering doesn't cut it, every method supports the possibility of enforcing a custom Item
type, and a custom CompositeKey
type where needed.
type CustomItem = {
pk: string
sk: string
name: string
}
type CustomCompositeKey = {
pk: string
sk: string
}
const { Item } = await MyEntity.get<CustomItem, CustomCompositeKey>({
pk: 'pk',
sk: 'sk' // โ
CustomCompositeKey expected
}) // โ
Item is of type: undefined | CustomItem
Overlaying at the Entity level is also possible. The overlay is passed down to every method, and type inference is fully deactivated:
const MyEntity = new Entity<CustomItem, CustomCompositeKey, typeof table>({
...,
table,
} as const)
await MyEntity.update({ pk, sk, name }) // โ
Overlay CustomItem is used
await MyEntity.delete<CustomItem, { foo: "bar" }>({ foo: "bar" }) // โ
Entity overlays can still be overridden
Write operations condition
and read operations attributes
options are also typed as the applied overlay keys and filter the response properties:
const { Item } = await MyEntity.get({ pk, sk }, { attributes: ['incorrect'] }) // โ Errors
const { Item } = await MyEntity.get({ pk, sk }, { attributes: ['name'] }) // โ
Item is of type { name: string }
The inferred or overlayed entity items type can be obtained through the EntityItem
utility type:
import type { EntityItem } from 'dynamodb-toolbox'
const listUsers = async (): Promise<EntityItem<typeof UserEntity>[]> => {
const { Items } = await UserEntity.query(...)
return Items
}
Sometimes, it can be useful to dynamically set an entity operation options. For instance:
const queryOptions = {}
if (!isSuperadmin(user)) {
queryOptions.beginsWith = 'USER'
}
const { Item } = await MyEntity.query(pk, { attributes: ['name', 'age'], ...queryOptions })
Sadly, in TS this throws an error, as getOptions
is typed as {}
. Using a non-generic GetOptions
type also throws an error as the entity attribute names are hardly typed, and string
is not assignable to the attributes
or conditions
options.
For this purpose, DynamoDB-Toolbox exposes GetOptions
, PutOptions
, DeleteOptions
, UpdateOptions
& QueryOptions
utility types:
import type { QueryOptions } from 'dynamodb-toolbox'
const queryOptions: QueryOptions<typeof MyEntity> = {}
if (!isSuperadmin(user)) {
queryOptions.beginsWith = 'USER'
}
const { Item } = await MyEntity.query(pk, { attributes: ['name', 'age'], ...queryOptions })
Contributions, ideas and bug reports are welcome and greatly appreciated. Please add issues for suggestions and bug reports or create a pull request. You can also contact me on Twitter: @jeremy_daly.