Giter VIP home page Giter VIP logo

dynongo's Introduction

dynongo

Build Status codecov

MongoDB like syntax for DynamoDB

Installation

npm install --save dynongo

Usage

Connect

First of all, we have to connect with the database.

const db = require('dynongo');

db.connect();

Please use IAM roles or environment variables to connect with the dynamodb database. This way, no keys have to be embedded in your code. You can find more information on the SDK page.

If you still want to use embedded credentials, you can by providing an accessKeyId, secretAccessKey and an optional region property.

db.connect({
    accessKeyId: 'AKIAI44QH8DHBEXAMPLE',
    secretAccessKey: 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY',
    region: 'us-west-1'
});

Or if you rather work with temporary security credentials, you can do that as well.

db.connect({
	accessKeyId: 'AKIAI44QH8DHBEXAMPLE',
    secretAccessKey: 'wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY',
	sessionToken: 'AQoDYXdzEJr...<remainder of security token>',
	region: 'us-west-1'
});

DynamoDB Local

It is possible to connect to a local DynamoDB database by setting the local property to true. It will use port 8000 by default, but if you want to change that port, you can provide a localPort property.

db.connect({
    local: true,
    host: '192.168.5.5',            // localhost if not provided
    localPort: 4444                 // 8000 if not provided
});

Prefixing tables

It's a good thing to prefix the tables with the name of the project and maybe the environment like production or staging. Instead of always repeating those names every time you want to query the table, you can provide the prefix and prefix delimiter once. The default delimiter is the ..

db.connect({
    prefix: 'myapp-development',
    prefixDelimiter: '-'            // . if not provided
});

Tables

In order for the developer to execute methods on a table, you have to retrieve the table object from the database.

const Employee = db.table('Employee');

The table name will be automatically prefixed by the prefix provided in the connection object.

If you provided a prefix in the connection object but you don't want that for a specific table, you could ask for a raw table. A raw table is like a regular table without the prefix.

const Employee = db.rawTable('Employee');

Methods

find

Employee.find({Organisation: 'Amazon'}).where({Salary: {$gt: 3000}}).select('FirstName Name').exec()
    .then(employees => {
        // => [{FirstName: 'Foo', Name: 'Bar'}]
    });

findOne

Employee.findOne({Organisation: 'Amazon'}).where({Salary: {$between: [3000, 4000]}}).select('FirstName Name').exec()
    .then(employee => {
        // => {FirstName: 'Foo', Name: 'Bar'}
    });

count

Employee.find({Organisation: 'Amazon'}).where({Salary: {$gt: 3000}}).count().exec()
    .then(count => {
        // => 8
    });

insert

 Employee.insert({Organisation: 'Amazon', Email: '[email protected]'}, {Title: 'CFO', FirstName: 'Foo', Name: 'Bar', Salary: 4500}).exec()
    .then(employee => {
        // => {FirstName: 'Foo', Name: 'Bar', Salary: 4500, Title: 'CFO', Organisation: 'Amazon', Email: '[email protected]'}
    });

update

The first parameter in the update method is the primary key (hash + range) and the second method is a query that defines the updates of the fields.

Employee.update({Organisation: 'Amazon', Email: '[email protected]'}, {$set: {Title: 'CTO'}, $inc: {Salary: 150}, $push: {Hobby: {$each: ['swimming', 'walking']}}}).exec()
    .then(employee => {
        // => {FirstName: 'Foo', Name: 'Bar', Salary: 4650, Title: 'CTO', Organisation: 'Amazon', Email: '[email protected]', Hobby: ['cycling', 'swimming', 'walking']}
    });

You can use $unshift to prepend a list with one or multiple values.

Employee.update({Organisation: 'Amazon', Email: '[email protected]'}, {$unshift: {Hobby: 'programming'}}}).exec()
    .then(employee => {
        // => {FirstName: 'Foo', Name: 'Bar', Salary: 4650, Title: 'CTO', Organisation: 'Amazon', Email: '[email protected]', Hobby: ['programming', 'cycling', 'swimming', 'walking']}
    });

If no Amazon employee exists with that email address exists, the method will fail.

You can also add extra conditions, for instance if we want to increase the salary by $150 only if the current salary is less then $4500.

Employee.update({Organisation: 'Amazon', Email: '[email protected]'}, {$inc: {Salary: 150}}).where({Salary: {$lt: 4500}}).exec()
    .catch(err => {
        // ConditionalCheckFailedException: The conditional request failed
    });

remove

The remove method expects the primary key (hash + range).

Employee.remove({Organisation: 'Amazon', Email: '[email protected]'}).exec()
    .then(() => {
        // => removed
    });

findOneAndRemove

This method is the same as the remove method, except that it will return the removed record..

Employee.findOneAndRemove({Organisation: 'Amazon', Email: '[email protected]'}).exec()
    .then(result => {
        // => {Organisation: 'Amazon', Email: '[email protected]'}
    });

Transactions

The library also supports transactions. Transactions simplify the developer experience of making coordinated, all-or-nothing changes to multiple items both within and across tables. You can only provide up to 10 transaction requests per transaction.

Read Transactions

import dynongo from 'dynongo';

const result = await dynongo
	.transactRead(
		dynongo.table('User')
			.find({Id: '1234', Key: 'BankRoll'}),
		dynongo.table('BankAccount')
			.find({Key: 'Salary'})
	)
	.exec();

//=> [{Id: '1234', Key: 'BankRoll', Value: 100}, {Key: 'Salary', Value: 1500}]

Write Transactions

For instance, what if we want to increment the bankroll of a user, but only if we still have enough money on our own back account.

import dynongo from 'dynongo';

await dynongo
	.transactWrite(
		dynongo.table('User')
			.update({Id: '1234', Key: 'BankRoll'}, {$inc: {Amount: 150}})
	)
	.withConditions(
		dynongo.table('BankAccount')
			.find({Key: 'Salary'})
			.where({value: {$gte: 150}})
	)
	.exec();

List all the tables

You can retrieve a list of all the tables.

db.listTables().exec().then(tables => {
	console.log(tables);
	//=> ['foo', 'bar', 'baz']
});

If you passed in a prefix property in the connection object, only the tables with that prefix will be returned.

Paging

You can implement paging by using the startFrom() method together with the LastEvaluatedKey property returned when using the raw() method.

const result = Employee.find({Organisation: 'Amazon'}).where({Salary: {$gt: 3000}}).limit(1).raw().exec()
    .then(result => {
        /**
		 * {
		 *     "Items": [
		 *         { UserId: '1', FirstName: 'Foo', Name: 'Bar' }
		 *     ],
		 *     "Count": 1,
		 *     "ScannedCount": 1,
		 *     "LastEvaluatedKey": {
		 *         Organisation: 'Amazon',
		 *         UserId: '1'
		 *     }
		 * }
		 */

		// Retrieve the next page
		return Employee.find({Organisation: 'Amazon'}).where({Salary: {$gt: 3000}}).startFrom(result.LastEvaluatedKey).limit(1).raw().exec()
	})
	.then(result => {
        /**
		 * {
		 *     "Items": [
		 *         { UserId: '2', FirstName: 'Unicorn', Name: 'Rainbow' }
		 *     ],
		 *     "Count": 1,
		 *     "ScannedCount": 1,
		 *     "LastEvaluatedKey": {
		 *         Organisation: 'Amazon',
		 *         UserId: '2'
		 *     }
		 * }
		 */
	});

You can also use dynongo-pager to make paging even easier.

Create a table

A table can be created by either calling create() on a table instance or by calling createTable on the database instance.

The first way is by calling the create() method.

const Employee = db.table('Employee');

const schema = {
    TableName: 'Employee',
    AttributeDefinitions: [
        { AttributeName: 'id', AttributeType: 'S' }
    ],
    KeySchema: [
        { AttributeName: 'id', KeyType: 'HASH' }
    ],
    ProvisionedThroughput: {
        ReadCapacityUnits: 1,
        WriteCapacityUnits: 1
    }
};

Employee.create(schema).exec()
    .then(() => {
        // => Table is being created
    });

The second way is by calling the createTable() method.

db.createTable(schema).exec()
    .then(() => {
        // Table is being created
    });

This is shorthand for the first method.

Awaiting the result

Creating a table can take a while. The previous examples do not wait for the action to be completed. But there might be use cases where you have to wait untill the table is created entirely before continuing. This can be done with the wait() method.

db.createTable(schema).wait().exec()
    .then(() => {
        // Table is created
    });

This will make sure the table is polled every 1000 milliseconds untill the status of the table is active. If you want to poll at another speed, you can by providing the number of milliseconds in the wait method.

db.createTable(schema).wait(5000).exec();

This will poll the status of the table every 5 seconds instead of every second.

Drop a table

A table can be dropped by either calling drop() on a table instance or by calling dropTable() on the database instance.

The first way is by calling the drop() method.

const Employee = db.table('Employee');

Employee.drop().exec()
    .then(() => {
        // => Table is being dropped
    });

The second way is by calling the dropTable() method.

db.dropTable('Employee').exec()
    .then(() => {
        // => Table is being dropped
    })

This method is just a shorthand method for the first example.

Awaiting the result

Dropping a table can take a while, especially when the table has a lot of data. The previous examples do not wait for the action to be completed. But there might be use cases where you have to wait untill the table is removed entirely before continuing. This can be done with the wait() method.

db.dropTable('Employee').wait().exec()
    .then(() => {
        // => Table is dropped
    })

This will make sure the table is polled every 1000 milliseconds untill the table does not exist anymore. If you want to poll at another speed, you can by providing the number of milliseconds in the wait method.

db.dropTable('Employee').wait(5000).exec();

This will poll the status of the table every 5 seconds instead of every second.

Related

License

MIT © Sam Verschueren

dynongo's People

Contributors

samverschueren avatar simonjang avatar

Watchers

James Cloos avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.