Lightweight client library for working with DynamoDB in Node.js. Written in Typescript with a Promise-based API.
This library tries to expose the natural DynamoDB way of doing things as directly as possible, while adding a few convenient helpers and shortcuts.
Things it does:
- Supports reading and writing items as plain Javascript objects. (more details below)
- Adds a few convenience patterns and shortcuts.
- Handles some common patterns for you, like using
attribute_not_exists()
expressions.
Things it does NOT do:
- Doesn't have a schema or do any data validation.
- Doesn't provide a DAO style interface.
Also note, so far this library is just a partial implementation of the DynamoDB API. Some big features missing are: no helpers for Query or Scan.
One thing this library does is automatically map from Javascript to Dynamo's AttributeValue tagging scheme. The mapping looks like:
plain Javascript object | AttributeValue |
---|---|
null or undefined
|
{ NULL: true } |
typeof is string
|
{ S: ... } |
typeof is boolean
|
{ BOOL: ... } |
typeof is number
|
{ N: ... } |
Array.isArray is true |
{ L: [ ... ] } (aka List) |
all other values |
{ M: { ... } } (aka Map) |
To get started, you should install and initialize the aws-sdk
library seperately (version 2.322.0 or later should work),
then create a new DynamoDB service object. Example:
import AWS from 'aws-sdk';
const client = new AWS.DynamoDB({
apiVersion: '2012-08-10',
region: 'us-east-1'
endpoint: endpoint
});
Once you have the client instance, create one or more Table instances.
import { Table } from 'minimal-dynamodb-client'
const table = new Table({
client,
tableName: 'my-table',
primaryKey: 'key'
});
The primaryKey
is optional but highly recommended, This should be the field name for the table's
primary key. (or one of them, if there are multiple). If provided, this library will use it for
some convenient patterns.
When running locally it's recommended that devs launch this awesome Docker container:
docker run -p 7042:8000 -it --rm instructure/dynamo-local-admin
Once running you can use the web interface at http://localhost:7042 to browse your data.
This library adds a CreateTable helper. It's recommended to call this when the app is running locally, to set up all your table(s) on the local DynamoDB instance.
Example:
if (localMode) {
await table.createTable();
}
It's not recommended to use createTable
in production. Instead your production tables should be
configured by a seperate process. (using Terraform or CDK or etc)
Calls GetItem.
The 'key' can either be a string or an object.
If the key is a string, then we fetch the item with that primary key value. (using the table's 'primaryKey')
If the key is an object, then it's converted to an AttributeValue map (see below) and then used as the "Key" value
Examples:
data = await table.getItem("user-123");
data = await table.getItem({ specificPrimaryKey: "value-123" });
Calls PutItem.
itemData
is the object to set. This object should include one of the table's primary keys, or else Dynamo
will complain.
Available options:
option | description |
---|---|
noOverwrite | Don't overwrite this item if it already exists. (using an attribute_not_exists expression) |
primaryKey | Key to use with noOverwrite (defaults to the table's primaryKey) |
Examples:
await table.putItem({
key: 'user-123',
name: 'Name',
address: '123 Address'
})
await table.putItem(userData, { noOverwrite: true });
Calls UpdateItem
key
is either a string or object, and works the same as the key in getItem
. If it's a string then the table's primaryKey is used.
changes
is either an Array of {field, value}
objects, or a single object of fields to set. Dynamo allows
you to change multiple fields in a single item with one operation.
// Set a single field "name" to value "Alice":
await table.updateItem(key, { name: 'Alice' })
// Set "name" to "Alice" and "city" to "Denver"
await table.updateItem(key, { name: 'Alice' city: 'Denver' })
// Set a single field "name" to value "Alice":
await table.updateItem(key, [{ field: 'name', value: 'Alice' }])
// Set "name" to "Alice" and "city" to "Denver"
await table.updateItem(key, [{ field: 'name', value: 'Alice' },{ field: 'city', value: 'Denver' }])
If the item has nested Map values, then we can update the contents of those maps. For this,
you can call updateItem
with an array of changes, and pass a list as the field
.
For example, let's say that the item is:
{
key: 'user123',
name: 'Alice',
friends: {
user456: {
accepted: false
}
}
}
We can update the nested "accepted" value with:
await table.updateItem(key, [{
field: [ 'friends', 'user456', 'accepted' ],
value: true
}])
Calls DeleteItem
The key
takes the same values as getItem().
Example:
await table.deleteItem(key);
Deletes one or more fields out of an item. This uses UpdateItem with a REMOVE expression. The key
takes the same values as getItem().
await table.deleteFields(key, [ "needsMigration" ]);
Deletes one field from an item. Convenience method for calling deleteFields with a single item.
await table.deleteField(key, "needsMigration");
Appends an item onto a list value. This uses UpdateItem with a list_append()
expression. The key
takes the same values as getItem().
Example:
If the item is equal to:
{
key: 'key1',
list: ['a', 'b']
}
Then we can add an item with
await table.listAppend('key1', 'list', 'c')