{"id":13561890,"url":"https://github.com/baseprime/dynamodb","last_synced_at":"2025-10-27T04:46:27.984Z","repository":{"id":19854889,"uuid":"88102005","full_name":"baseprime/dynamodb","owner":"baseprime","description":"DynamoDB data mapper for Node.js","archived":false,"fork":false,"pushed_at":"2024-05-30T21:08:35.000Z","size":567,"stargazers_count":295,"open_issues_count":60,"forks_count":88,"subscribers_count":7,"default_branch":"master","last_synced_at":"2025-03-29T03:34:00.515Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/baseprime.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2017-04-12T22:31:35.000Z","updated_at":"2024-12-28T03:11:32.000Z","dependencies_parsed_at":"2024-06-07T01:57:16.951Z","dependency_job_id":"678c6b70-3b1c-4f08-b621-9dffeabe1e00","html_url":"https://github.com/baseprime/dynamodb","commit_stats":{"total_commits":204,"total_committers":16,"mean_commits":12.75,"dds":0.5882352941176471,"last_synced_commit":"ed02985620cfbb0c63263de012c08e2627a8a295"},"previous_names":[],"tags_count":8,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/baseprime%2Fdynamodb","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/baseprime%2Fdynamodb/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/baseprime%2Fdynamodb/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/baseprime%2Fdynamodb/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/baseprime","download_url":"https://codeload.github.com/baseprime/dynamodb/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247047071,"owners_count":20874765,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-01T13:01:02.304Z","updated_at":"2025-10-27T04:46:22.927Z","avatar_url":"https://github.com/baseprime.png","language":"JavaScript","readme":"\n`dynamodb` is a [DynamoDB][5] data mapper for [node.js][1].\n\n## Features\n* Simplified data modeling and mapping to DynamoDB types\n* Advanced chainable apis for [query](#query) and [scan](#scan) operations\n* Data validation\n* [Autogenerating UUIDs](#uuid)\n* [Global Secondary Indexes](#global-indexes)\n* [Local Secondary Indexes](#local-secondary-indexes)\n* [Parallel Scans](#parallel-scan)\n\n## Installation\n\n    npm install dynamodb\n\n## Getting Started\nFirst, you need to configure the [AWS SDK][2] with your credentials.\n\n```js\nvar dynamo = require('dynamodb');\ndynamo.AWS.config.loadFromPath('credentials.json');\n```\n\nWhen running on EC2 its recommended to leverage EC2 IAM roles. If you have configured your instance to use IAM roles, DynamoDB will automatically select these credentials for use in your application, and you do not need to manually provide credentials in any other format.\n\n```js\nvar dynamo = require('dynamodb');\ndynamo.AWS.config.update({region: \"REGION\"}); // region must be set\n```\n\nYou can also directly pass in your access key id, secret and region.\n  * Its recommend you not hard-code credentials inside an application. Use this method only for small personal scripts or for testing purposes.\n\n```js\nvar dynamo = require('dynamodb');\ndynamo.AWS.config.update({accessKeyId: 'AKID', secretAccessKey: 'SECRET', region: \"REGION\"});\n```\n\nCurrently the following region codes are available in Amazon:\n\n|      Code      |           Name           |\n| -------------- | ------------------------ |\n| ap-northeast-1 | Asia Pacific (Tokyo)     |\n| ap-southeast-1 | Asia Pacific (Singapore) |\n| ap-southeast-2 | Asia Pacific (Sydney)    |\n| eu-central-1   | EU (Frankfurt)           |\n| eu-west-1      | EU (Ireland)             |\n| sa-east-1      | South America (Sao Paulo)|\n| us-east-1      | US East (N. Virginia)    |\n| us-west-1      | US West (N. California)  |\n| us-west-2      | US West (Oregon)         |\n\n### Define a Model\nModels are defined through the toplevel define method.\n\n```js\nvar Account = dynamo.define('Account', {\n  hashKey : 'email',\n\n  // add the timestamp attributes (updatedAt, createdAt)\n  timestamps : true,\n\n  schema : {\n    email   : Joi.string().email(),\n    name    : Joi.string(),\n    age     : Joi.number(),\n    roles   : dynamo.types.stringSet(),\n    settings : {\n      nickname      : Joi.string(),\n      acceptedTerms : Joi.boolean().default(false)\n    }\n  }\n});\n```\n\nModels can also be defined with hash and range keys.\n\n```js\nvar BlogPost = dynamo.define('BlogPost', {\n  hashKey : 'email',\n  rangeKey : ‘title’,\n  schema : {\n    email   : Joi.string().email(),\n    title   : Joi.string(),\n    content : Joi.binary(),\n    tags   : dynamo.types.stringSet(),\n  }\n});\n```\n\n### Create Tables for all defined modules\n\n```js\ndynamo.createTables(function(err) {\n  if (err) {\n    console.log('Error creating tables: ', err);\n  } else {\n    console.log('Tables has been created');\n  }\n});\n```\n\nWhen creating tables you can pass specific throughput settings for any defined models.\n\n```js\ndynamo.createTables({\n  'BlogPost': {readCapacity: 5, writeCapacity: 10},\n  'Account': {readCapacity: 20, writeCapacity: 4}\n}, function(err) {\n  if (err) {\n    console.log('Error creating tables: ', err);\n  } else {\n    console.log('Tables has been created');\n  }\n});\n```\n\n### Delete Table\n\n```js\nBlogPost.deleteTable(function(err) {\n  if (err) {\n    console.log('Error deleting table: ', err);\n  } else {\n    console.log('Table has been deleted');\n  }\n});\n```\n\n### Schema Types\nDynamoDB provides the following schema types:\n\n* String\n* Number\n* StringSet\n* NumberSet\n* Boolean\n* Date\n* UUID\n* TimeUUID\n\n#### UUID\nUUIDs can be declared for any attributes, including hash and range keys. By\nDefault, the uuid will be automatically generated when attempting to create\nthe model in DynamoDB.\n\n```js\nvar Tweet = dynamo.define('Tweet', {\n  hashKey : 'TweetID',\n  timestamps : true,\n  schema : {\n    TweetID : dynamo.types.uuid(),\n    content : Joi.string(),\n  }\n});\n```\n\n### Configuration\nYou can configure dynamo to automatically add `createdAt` and `updatedAt` timestamp attributes when\nsaving and updating a model. `updatedAt` will only be set when updating a record and will not be set on initial creation of the model.\n\n```js\nvar Account = dynamo.define('Account', {\n  hashKey : 'email',\n\n  // add the timestamp attributes (updatedAt, createdAt)\n  timestamps : true,\n\n  schema : {\n    email : Joi.string().email(),\n  }\n});\n```\n\nIf you want dynamo to handle timestamps, but only want some of them, or want your\ntimestamps to be called something else, you can override each attribute individually:\n\n```js\nvar Account = dynamo.define('Account', {\n  hashKey : 'email',\n\n  // enable timestamps support\n  timestamps : true,\n\n  // I don't want createdAt\n  createdAt: false,\n\n  // I want updatedAt to actually be called updateTimestamp\n  updatedAt: 'updateTimestamp'\n\n  schema : {\n    email : Joi.string().email(),\n  }\n});\n```\n\nYou can override the table name the model will use.\n\n```js\nvar Event = dynamo.define('Event', {\n  hashKey : 'name',\n  schema : {\n    name : Joi.string(),\n    total : Joi.number()\n  },\n\n  tableName: 'deviceEvents'\n});\n```\n\nif you set the tableName to a function, dynamo will use the result of the function as the active table to use.\nUseful for storing time series data.\n\n```js\nvar Event = dynamo.define('Event', {\n  hashKey : 'name',\n  schema : {\n    name : Joi.string(),\n    total : Joi.number()\n  },\n\n  // store monthly event data\n  tableName: function () {\n    var d = new Date();\n    return ['events', d.getFullYear(), d.getMonth() + 1].join('_');\n  }\n});\n```\n\nAfter you've defined your model you can configure the table name to use.\nBy default, the table name used will be the lowercased and pluralized version\nof the name you provided when defining the model.\n\n```js\nAccount.config({tableName: 'AccountsTable'});\n```\n\nYou can also pass in a custom instance of the aws-sdk DynamoDB client\n```js\nvar dynamodb = new AWS.DynamoDB();\nAccount.config({dynamodb: dynamodb});\n\n// or globally use custom DynamoDB instance\n// all defined models will now use this driver\ndynamo.dynamoDriver(dynamodb);\n```\n\n### Saving Models to DynamoDB\nWith your models defined, we can start saving them to DynamoDB.\n\n```js\nAccount.create({email: 'foo@example.com', name: 'Foo Bar', age: 21}, function (err, acc) {\n  console.log('created account in DynamoDB', acc.get('email'));\n});\n```\n\nYou can also first instantiate a model and then save it.\n\n```js\n// callbacks\nvar acc = new Account({email: 'test@example.com', name: 'Test Example'});\nacc.save(function (err) {\n  if( err ) {\n    console.log('error in saving account', err);\n  } else {\n    console.log('created account in DynamoDB', acc.get('email'));\n  }\n});\n\n// async/await (Promise)\ntry {\n  var acc = new Account({email: 'test@example.com', name: 'Test Example'});\n  await acc.save();\n  console.log('created account in DynamoDB', acc.get('email'))\n} catch( err ) {\n  console.log('error in saving account', err);\n}\n```\n\nSaving models that require range and hashkeys are identical to ones with only\nhashkeys.\n\n```js\nBlogPost.create({\n  email: 'werner@example.com',\n  title: 'Expanding the Cloud',\n  content: 'Today, we are excited to announce the limited preview...'\n  }, function (err, post) {\n    console.log('created blog post', post.get('title'));\n  });\n```\n\nPass an array of items and they will be saved in parallel to DynamoDB.\n\n```js\nvar item1 = {email: 'foo1@example.com', name: 'Foo 1', age: 10};\nvar item2 = {email: 'foo2@example.com', name: 'Foo 2', age: 20};\nvar item3 = {email: 'foo3@example.com', name: 'Foo 3', age: 30};\n\nAccount.create([item1, item2, item3], function (err, acccounts) {\n  console.log('created 3 accounts in DynamoDB', accounts);\n});\n```\n\nUse expressions api to do conditional writes\n\n```js\n  var params = {};\n  params.ConditionExpression = '#i \u003c\u003e :x';\n  params.ExpressionAttributeNames = {'#i' : 'id'};\n  params.ExpressionAttributeValues = {':x' : 123};\n\n  User.create({id : 123, name : 'Kurt Warner' }, params, function (error, acc) { ... });\n```\n\nUse the `overwrite` option to prevent over writing of existing records.\n  * By default `overwrite` is set to true, allowing create operations to overwrite existing records\n```js\n  // setting overwrite to false will generate\n  // the same Condition Expression as in the previous example\n  User.create({id : 123, name : 'Kurt Warner' }, {overwrite : false}, function (error, acc) { ... });\n```\n\n### Updating\n\nWhen updating a model the hash and range key attributes must be given, all\nother attributes are optional\n\n```js\n// update the name of the foo@example.com account\nAccount.update({email: 'foo@example.com', name: 'Bar Tester'}, function (err, acc) {\n  console.log('update account', acc.get('name'));\n});\n```\n\n`Model.update` accepts options to pass to DynamoDB when making the updateItem request\n\n```js\nAccount.update({email: 'foo@example.com', name: 'Bar Tester'}, {ReturnValues: 'ALL_OLD'}, function (err, acc) {\n  console.log('update account', acc.get('name')); // prints the old account name\n});\n\n// Only update the account if the current age of the account is 21\nAccount.update({email: 'foo@example.com', name: 'Bar Tester'}, {expected: {age: 22}}, function (err, acc) {\n  console.log('update account', acc.get('name'));\n});\n\n// setting an attribute to null will delete the attribute from DynamoDB\nAccount.update({email: 'foo@example.com', age: null}, function (err, acc) {\n  console.log('update account', acc.get('age')); // prints null\n});\n```\n\nYou can also pass what action to perform when updating a given attribute\nUse $add to increment or decrement numbers and add values to sets\n\n```js\nAccount.update({email : 'foo@example.com', age : {$add : 1}}, function (err, acc) {\n  console.log('incremented age by 1', acc.get('age'));\n});\n\nBlogPost.update({\n  email : 'werner@example.com',\n  title : 'Expanding the Cloud',\n  tags  : {$add : 'cloud'}\n}, function (err, post) {\n  console.log('added single tag to blog post', post.get('tags'));\n});\n\nBlogPost.update({\n  email : 'werner@example.com',\n  title : 'Expanding the Cloud',\n  tags  : {$add : ['cloud', 'dynamodb']}\n}, function (err, post) {\n  console.log('added tags to blog post', post.get('tags'));\n});\n```\n\n$del will remove values from a given set\n\n```js\nBlogPost.update({\n  email : 'werner@example.com',\n  title : 'Expanding the Cloud',\n  tags  : {$del : 'cloud'}\n}, function (err, post) {\n  console.log('removed cloud tag from blog post', post.get('tags'));\n});\n\nBlogPost.update({\n  email : 'werner@example.com',\n  title : 'Expanding the Cloud',\n  tags  : {$del : ['aws', 'node']}\n}, function (err, post) {\n  console.log('removed multiple tags', post.get('tags'));\n});\n```\n\nUse the expressions api to update nested documents\n\n```js\nvar params = {};\n  params.UpdateExpression = 'SET #year = #year + :inc, #dir.titles = list_append(#dir.titles, :title), #act[0].firstName = :firstName ADD tags :tag';\n  params.ConditionExpression = '#year = :current';\n  params.ExpressionAttributeNames = {\n    '#year' : 'releaseYear',\n    '#dir' : 'director',\n    '#act' : 'actors'\n  };\n\n  params.ExpressionAttributeValues = {\n    ':inc' : 1,\n    ':current' : 2001,\n    ':title' : ['The Man'],\n    ':firstName' : 'Rob',\n    ':tag' : dynamo.Set(['Sports', 'Horror'], 'S')\n  };\n\nMovie.update({title : 'Movie 0', description : 'This is a description'}, params, function (err, mov) {});\n```\n\n### Deleting\nYou delete items in DynamoDB using the hashkey of model\nIf your model uses both a hash and range key, than both need to be provided\n\n```js\nAccount.destroy('foo@example.com', function (err) {\n  console.log('account deleted');\n});\n\n// Destroy model using hash and range key\nBlogPost.destroy('foo@example.com', 'Hello World!', function (err) {\n  console.log('post deleted')\n});\n\nBlogPost.destroy({email: 'foo@example.com', title: 'Another Post'}, function (err) {\n  console.log('another post deleted')\n});\n```\n\n`Model.destroy` accepts options to pass to DynamoDB when making the deleteItem request\n\n```js\nAccount.destroy('foo@example.com', {ReturnValues: true}, function (err, acc) {\n  console.log('account deleted');\n  console.log('deleted account name', acc.get('name'));\n});\n\nAccount.destroy('foo@example.com', {expected: {age: 22}}, function (err) {\n  console.log('account deleted if the age was 22');\n```\n\n\nUse expression apis to perform conditional deletes\n\n```js\nvar params = {};\nparams.ConditionExpression = '#v = :x';\nparams.ExpressionAttributeNames = {'#v' : 'version'};\nparams.ExpressionAttributeValues = {':x' : '2'};\n\nUser.destroy({id : 123}, params, function (err, acc) {});\n```\n\n### Loading models from DynamoDB\nThe simpliest way to get an item from DynamoDB is by hashkey.\n\n```js\nAccount.get('test@example.com', function (err, acc) {\n  console.log('got account', acc.get('email'));\n});\n```\n\nPerform the same get request, but this time peform a consistent read.\n\n```js\nAccount.get('test@example.com', {ConsistentRead: true}, function (err, acc) {\n  console.log('got account', acc.get('email'));\n});\n```\n\n`Model.get` accepts any options that DynamoDB getItem request supports. For\nexample:\n\n```js\nAccount.get('test@example.com', {ConsistentRead: true, AttributesToGet : ['name','age']}, function (err, acc) {\n  console.log('got account', acc.get('email'))\n  console.log(acc.get('name'));\n  console.log(acc.get('age'));\n  console.log(acc.get('email')); // prints null\n});\n```\n\nGet a model using hash and range key.\n\n```js\n// load up blog post written by Werner, titled DynamoDB Keeps Getting Better and cheaper\nBlogPost.get('werner@example.com', 'dynamodb-keeps-getting-better-and-cheaper', function (err, post) {\n  console.log('loaded post by range and hash key', post.get('content'));\n});\n```\n\n`Model.get` also supports passing an object which contains hash and range key\nattributes to load up a model\n\n```js\nBlogPost.get({email: 'werner@example.com', title: 'Expanding the Cloud'}, function (err, post) {\n  console.log('loded post', post.get('content'));\n});\n```\n\nUse expressions api to select which attributes you want returned\n\n```js\n  User.get({ id : '123456789'},{ ProjectionExpression : 'email, age, settings.nickname' }, function (err, acc) {});\n```\n\n### Query\nFor models that use hash and range keys DynamoDB provides a flexible and\nchainable query api\n\n```js\n// query for blog posts by werner@example.com\nBlogPost\n  .query('werner@example.com')\n  .exec(callback);\n\n// same as above, but load all results\nBlogPost\n  .query('werner@example.com')\n  .loadAll()\n  .exec(callback);\n\n// only load the first 5 posts by werner\nBlogPost\n  .query('werner@example.com')\n  .limit(5)\n  .exec(callback);\n\n// query for posts by werner where the tile begins with 'Expanding'\nBlogPost\n  .query('werner@example.com')\n  .where('title').beginsWith('Expanding')\n  .exec(callback);\n\n// return only the count of documents that begin with the title Expanding\nBlogPost\n  .query('werner@example.com')\n  .where('title').beginsWith('Expanding')\n  .select('COUNT')\n  .exec(callback);\n\n// only return title and content attributes of 10 blog posts\n// that begin with the title Expanding\nBlogPost\n  .query('werner@example.com')\n  .where('title').beginsWith('Expanding')\n  .attributes(['title', 'content'])\n  .limit(10)\n  .exec(callback);\n\n// sorting by title ascending\nBlogPost\n  .query('werner@example.com')\n  .ascending()\n  .exec(callback)\n\n// sorting by title descending\nBlogPost\n  .query('werner@example.com')\n  .descending()\n  .exec(callback)\n\n// All query options are chainable\nBlogPost\n  .query('werner@example.com')\n  .where('title').gt('Expanding')\n  .attributes(['title', 'content'])\n  .limit(10)\n  .ascending()\n  .loadAll()\n  .exec(callback);\n```\n\nDynamoDB supports all the possible KeyConditions that DynamoDB currently\nsupports.\n\n```js\nBlogPost\n  .query('werner@example.com')\n  .where('title').equals('Expanding')\n  .exec();\n\n// less than equals\nBlogPost\n  .query('werner@example.com')\n  .where('title').lte('Expanding')\n  .exec();\n\n// less than\nBlogPost\n  .query('werner@example.com')\n  .where('title').lt('Expanding')\n  .exec();\n\n// greater than\nBlogPost\n  .query('werner@example.com')\n  .where('title').gt('Expanding')\n  .exec();\n\n// greater than equals\nBlogPost\n  .query('werner@example.com')\n  .where('title').gte('Expanding')\n  .exec();\n\nBlogPost\n  .query('werner@example.com')\n  .where('title').beginsWith('Expanding')\n  .exec();\n\nBlogPost\n  .query('werner@example.com')\n  .where('title').between('foo@example.com', 'test@example.com')\n  .exec();\n```\n\nQuery Filters allow you to further filter results on non-key attributes.\n\n```js\nBlogPost\n  .query('werner@example.com')\n  .where('title').equals('Expanding')\n  .filter('tags').contains('cloud')\n  .exec();\n```\n\nExpression Filters also allow you to further filter results on non-key attributes.\n\n```javascript\nBlogPost\n  .query('werner@example.com')\n  .filterExpression('#title \u003c :t')\n  .expressionAttributeValues({ ':t' : 'Expanding' })\n  .expressionAttributeNames({ '#title' : 'title'})\n  .projectionExpression('#title, tag')\n  .exec();\n```\n\nSee the queryFilter.js [example][0] for more examples of using query filters\n\n#### Global Indexes\nFirst, define a model with a global secondary index.\n\n```js\nvar GameScore = dynamo.define('GameScore', {\n  hashKey : 'userId',\n  rangeKey : 'gameTitle',\n  schema : {\n    userId           : Joi.string(),\n    gameTitle        : Joi.string(),\n    topScore         : Joi.number(),\n    topScoreDateTime : Joi.date(),\n    wins             : Joi.number(),\n    losses           : Joi.number()\n  },\n  indexes : [{\n    hashKey : 'gameTitle', rangeKey : 'topScore', name : 'GameTitleIndex', type : 'global'\n  }]\n});\n```\n\nNow we can query against the global index\n\n```js\nGameScore\n  .query('Galaxy Invaders')\n  .usingIndex('GameTitleIndex')\n  .descending()\n  .exec(callback);\n```\n\nWhen can also configure the attributes projected into the index.\nBy default all attributes will be projected when no Projection parameter is\npresent\n\n```js\nvar GameScore = dynamo.define('GameScore', {\n  hashKey : 'userId',\n  rangeKey : 'gameTitle',\n  schema : {\n    userId           : Joi.string(),\n    gameTitle        : Joi.string(),\n    topScore         : Joi.number(),\n    topScoreDateTime : Joi.date(),\n    wins             : Joi.number(),\n    losses           : Joi.number()\n  },\n  indexes : [{\n    hashKey : 'gameTitle',\n    rangeKey : 'topScore',\n    name : 'GameTitleIndex',\n    type : 'global',\n    projection: { NonKeyAttributes: [ 'wins' ], ProjectionType: 'INCLUDE' } //optional, defaults to ALL\n\n  }]\n});\n```\n\nFilter items against the configured rangekey for the global index.\n\n```js\nGameScore\n  .query('Galaxy Invaders')\n  .usingIndex('GameTitleIndex')\n  .where('topScore').gt(1000)\n  .descending()\n  .exec(function (err, data) {\n    console.log(_.map(data.Items, JSON.stringify));\n  });\n```\n\n#### Local Secondary Indexes\nFirst, define a model using a local secondary index\n\n```js\nvar BlogPost = dynamo.define('Account', {\n  hashKey : 'email',\n  rangeKey : 'title',\n  schema : {\n    email             : Joi.string().email(),\n    title             : Joi.string(),\n    content           : Joi.binary(),\n    PublishedDateTime : Joi.date()\n  },\n\n  indexes : [{\n    hashKey : 'email', rangeKey : 'PublishedDateTime', type : 'local', name : 'PublishedIndex'\n  }]\n});\n```\n\nNow we can query for blog posts using the secondary index\n\n```js\nBlogPost\n  .query('werner@example.com')\n  .usingIndex('PublishedIndex')\n  .descending()\n  .exec(callback);\n```\n\nCould also query for published posts, but this time return oldest first\n\n```js\nBlogPost\n  .query('werner@example.com')\n  .usingIndex('PublishedIndex')\n  .ascending()\n  .exec(callback);\n```\n\nFinally lets load all published posts sorted by publish date\n```js\nBlogPost\n  .query('werner@example.com')\n  .usingIndex('PublishedIndex')\n  .descending()\n  .loadAll()\n  .exec(callback);\n```\n\nLearn more about [secondary indexes][3]\n\n### Scan\nDynamoDB provides a flexible and chainable api for scanning over all your items\nThis api is very similar to the query api.\n\n```js\n// scan all accounts, returning the first page or results\nAccount.scan().exec(callback);\n\n// scan all accounts, this time loading all results\n// note this will potentially make several calls to DynamoDB\n// in order to load all results\nAccount\n  .scan()\n  .loadAll()\n  .exec(callback);\n\n// Load 20 accounts\nAccount\n  .scan()\n  .limit(20)\n  .exec();\n\n// Load All accounts, 20 at a time per request\nAccount\n  .scan()\n  .limit(20)\n  .loadAll()\n  .exec();\n\n// Load accounts which match a filter\n// only return email and created attributes\n// and return back the consumed capacity the request took\nAccount\n  .scan()\n  .where('email').gte('f@example.com')\n  .attributes(['email','created'])\n  .returnConsumedCapacity()\n  .exec();\n\n// Returns number of matching accounts, rather than the matching accounts themselves\nAccount\n  .scan()\n  .where('age').gte(21)\n  .select('COUNT')\n  .exec();\n\n// Start scan using start key\nAccount\n  .scan()\n  .where('age').notNull()\n  .startKey('foo@example.com')\n  .exec()\n```\n\nDynamoDB supports all the possible Scan Filters that DynamoDB currently supports.\n\n```js\n// equals\nAccount\n  .scan()\n  .where('name').equals('Werner')\n  .exec();\n\n// not equals\nAccount\n  .scan()\n  .where('name').ne('Werner')\n  .exec();\n\n// less than equals\nAccount\n  .scan()\n  .where('name').lte('Werner')\n  .exec();\n\n// less than\nAccount\n  .scan()\n  .where('name').lt('Werner')\n  .exec();\n\n// greater than equals\nAccount\n  .scan()\n  .where('name').gte('Werner')\n  .exec();\n\n// greater than\nAccount\n  .scan()\n  .where('name').gt('Werner')\n  .exec();\n\n// name attribute doesn't exist\nAccount\n  .scan()\n  .where('name').null()\n  .exec();\n\n// name attribute exists\nAccount\n  .scan()\n  .where('name').notNull()\n  .exec();\n\n// contains\nAccount\n  .scan()\n  .where('name').contains('ner')\n  .exec();\n\n// not contains\nAccount\n  .scan()\n  .where('name').notContains('ner')\n  .exec();\n\n// in\nAccount\n  .scan()\n  .where('name').in(['foo@example.com', 'bar@example.com'])\n  .exec();\n\n// begins with\nAccount\n  .scan()\n  .where('name').beginsWith('Werner')\n  .exec();\n\n// between\nAccount\n  .scan()\n  .where('name').between('Bar', 'Foo')\n  .exec();\n\n// multiple filters\nAccount\n  .scan()\n  .where('name').equals('Werner')\n  .where('age').notNull()\n  .exec();\n```\n\nYou can also use the new expressions api when filtering scans\n\n```javascript\nUser.scan()\n  .filterExpression('#age BETWEEN :low AND :high AND begins_with(#email, :e)')\n  .expressionAttributeValues({ ':low' : 18, ':high' : 22, ':e' : 'test1'})\n  .expressionAttributeNames({ '#age' : 'age', '#email' : 'email'})\n  .projectionExpression('#age, #email')\n  .exec();\n```\n\n### Parallel Scan\nParallel scans increase the throughput of your table scans.\nThe parallel scan operation is identical to the scan api.\nThe only difference is you must provide the total number of segments\n\n**Caution** you can easily consume all your provisioned throughput with this api\n\n```js\nvar totalSegments = 8;\n\nAccount.parallelScan(totalSegments)\n  .where('age').gte(18)\n  .attributes('age')\n  .exec(callback);\n\n// Load All accounts\nAccount\n  .parallelScan(totalSegments)\n  .exec()\n```\n\nMore info on [Parallel Scans][4]\n\n### Batch Get Items\n`Model.getItems` allows you to load multiple models with a single request to DynamoDB.\n\nDynamoDB limits the number of items you can get to 100 or 1MB of data for a single request.\nDynamoDB automatically handles splitting up into multiple requests to load all\nitems.\n\n```js\nAccount.getItems(['foo@example.com','bar@example.com', 'test@example.com'], function (err, accounts) {\n  console.log('loaded ' + accounts.length + ' accounts'); // prints loaded 3 accounts\n});\n\n// For models with range keys you must pass in objects of hash and range key attributes\nvar postKey1 = {email : 'test@example.com', title : 'Hello World!'};\nvar postKey2 = {email : 'test@example.com', title : 'Another Post'};\n\nBlogPost.getItems([postKey1, postKey2], function (err, posts) {\n  console.log('loaded posts');\n});\n```\n\n`Model.getItems` accepts options which will be passed to DynamoDB when making the batchGetItem request\n\n```js\n// Get both accounts, using a consistent read\nAccount.getItems(['foo@example.com','bar@example.com'], {ConsistentRead: true}, function (err, accounts) {\n  console.log('loaded ' + accounts.length + ' accounts'); // prints loaded 2 accounts\n});\n```\n\n### Streaming api\ndynamo supports a basic streaming api in addition to the callback\napi for `query`, `scan`, and `parallelScan` operations.\n\n```js\nvar stream = Account.parallelScan(4).exec();\n\nstream.on('readable', function () {\n  console.log('single parallel scan response', stream.read());\n});\n\nstream.on('end', function () {\n  console.log('Parallel scan of accounts finished');\n});\n\nvar querystream = BlogPost.query('werner@dynamo.com').loadAll().exec();\n\nquerystream.on('readable', function () {\n  console.log('single query response', stream.read());\n});\n\nquerystream.on('end', function () {\n  console.log('query for blog posts finished');\n});\n```\n\n### Dynamic Table Names\ndynamo supports dynamic table names, useful for storing time series data.\n\n```js\nvar Event = dynamo.define('Event', {\n  hashKey : 'name',\n  schema : {\n    name : Joi.string(),\n    total : Joi.number()\n  },\n\n  // store monthly event data\n  tableName: function () {\n    var d = new Date();\n    return ['events', d.getFullYear(), d.getMonth() + 1].join('_');\n  }\n});\n```\n\n### Logging\nLogging can be enabled to provide detailed information on data being sent and returned from DynamoDB.\nBy default logging is turned off.\n\n```js\ndynamo.log.level('info'); // enabled INFO log level\n```\n\nLogging can also be enabled / disabled at the model level.\n\n```js\nvar Account = dynamo.define('Account', {hashKey : 'email'});\nvar Event = dynamo.define('Account', {hashKey : 'name'});\n\nAccount.log.level('warn'); // enable WARN log level for Account model operations\n```\n\n## Examples\n\n```js\nvar dynamo = require('dynamodb');\n\nvar Account = dynamo.define('Account', {\n  hashKey : 'email',\n\n  // add the timestamp attributes (updatedAt, createdAt)\n  timestamps : true,\n\n  schema : {\n    email   : Joi.string().email(),\n    name    : Joi.string().required(),\n    age     : Joi.number(),\n  }\n});\n\nAccount.create({email: 'test@example.com', name : 'Test Account'}, function (err, acc) {\n  console.log('created account at', acc.get('created')); // prints created Date\n\n  acc.set({age: 22});\n\n  acc.update(function (err) {\n    console.log('updated account age');\n  });\n\n});\n```\n\nSee the [examples][0] for more working sample code.\n\n### Support\n\nDynamoDB is provided as-is, free of charge. For support, you have a few choices:\n\n- Ask your support question on [Stackoverflow.com](http://stackoverflow.com), and tag your question with **dynamodb**.\n- If you believe you have found a bug in dynamodb, please submit a support ticket on the [Github Issues page for dynamo](http://github.com/baseprime/dynamo/issues). We'll get to them as soon as we can.\n\n### Maintainers\n\n- [Greg Sabia Tucker](http://github.com/baseprime) ([@baseprime](https://twitter.com/bytecipher))\n\n## Authors\n\n- [Ryan Fitzgerald](http://github.com/ryanfitz) ([@ryanfitz](https://twitter.com/theryanfitz))\n\n### License\n\n(The MIT License)\n\nCopyright (c) 2016 Ryan Fitzgerald\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n\"Software\"), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE\nLIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION\nOF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION\nWITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n[0]: https://github.com/baseprime/dynamodb/tree/master/examples\n[1]: http://nodejs.org\n[2]: http://aws.amazon.com/sdkfornodejs\n[3]: http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/LSI.html\n[4]: http://aws.typepad.com/aws/2013/05/amazon-dynamodb-parallel-scans-and-other-good-news.html\n[5]: http://aws.amazon.com/dynamodb\n","funding_links":[],"categories":["JavaScript"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbaseprime%2Fdynamodb","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbaseprime%2Fdynamodb","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbaseprime%2Fdynamodb/lists"}