DoQmentDB - A Promise-Based DocumentDB Client
DoQmentDB is a tiny layer that provides the simplicity of MongoDB for DocumentDB users(support schema, hooks/middleware, atomic-transactions, udf and more).
Table of contents:
- Get Started
- Examples
- Changelog
- Database
- Collection
- Queries
- Operations
- Schema
- Atomic Transactions
- Middleware
Get Started
(1) You can install DoQmentDB using 2 different methods:
(2) Add to your project:
var DoqmentDB = ;
(3) Start Playing with DoqmentDB:
var DoQmentDB = ;// Create DocumentDB connectionvar connection = new DocumentClientHOST OPTIONS;// Pass connection and database-name, if `test` is not exist it will create one.var db = connection 'test';// Create a CollectionManager instance, if `users` is not exist it will create one.var users = db;// Using schemausers;// Add hooks(see `users` full example)users; // Each http function returns a `Promise` with two specific methods: success and error.users ; users ; users ;
Database
Create a DatabaseManager by passing connection
and databaseName
.
var DoQmentDB = ;// Create DocumentDB connectionvar connection = new DocumentClientHOST OPTIONS;// if `test` is not exist it will create onevar db = connection 'test';
create
Get name and crete new collection in the used db.
Usage: db.create(string)
Aliases: insert
Returns: Object
db ;
getDatabase
Return the used database.
Usage: db.getDatabase()
db ;
find
find collection by given object params.
Note: to return all documents, omit params argument or pass an empty object({}).
Usage: db.find(object[optional])
Returns: Array
db ; // Return all collections db ; // Return collections where id equal to `users`
findById
find collection by given string
id.
Usage: db.findById(string)
Returns: Object
db ;
findOrCreate
get object properties, search for collection, if it not exist create one.
Usage: db.findOrCreate(object)
Returns: Object
db ;
remove
get collection id as a String
, if it exist - remove it and return undefined
, else return false
.
Usage: db.remove(string)
Returns: undefined
or Boolean
db ;
use
get collection name and return CollectionManager
instance.
Note: if the given collection
is not exist it will create one.
Usage: var coll = db.use(string);
Returns: object
instanceof CollectionManager
var users = db; // This operation is not async
Collection
Create a CollectionManager by passing to .use
function a collection name.
var users = db;console; // Collection
create
get object properties, and create new document under the used collection.
Usage: users.create(object)
Aliases: insert
Returns: Object
users ; // { name: 'Ariel', admin: true, id: '8...31', _self: ... }
createOrUpdate
create a new document under the current collection, or update an existing document with the same id.
Usage: users.createOrUpdate(object)
Aliases: upsert
Returns: Object
users ; // { id: 'my_user_id', admin: true, _self: ... }
getCollection
return the used collection.
Usage: users.getCollection()
users ;
find
get object properties and return array of results.
Usage: users.find(object)
Note: to return all collections, omit params argument or pass an empty object({}).
Returns: Array
users ;
findOne
get object properties and return the first matching result.
Usage: users.findOne(object)
Returns: Object
users ;
findById
find document by giving a string
id.
Usage: users.findById(string)
Returns: Object
users ;
findAndRemove
get object properties to search, find the equivalents and remove them.
Usage: users.findAndRemove(object)
Returns: Array
Note: if you want support atomic-transactions(i.e: do things concurrently, e.g: distributed system),
you need use this method prefix with $
sign.
users ; // Using stored procedureusers ; // Remove all usersusers ;
findOneAndRemove
get object properties, and remove the first matching result.
Usage: users.findOneAndRemove(object)
Returns: undefined
or Boolean
Note: if you want support atomic-transactions(i.e: do things concurrently, e.g: distributed system),
you need use this method prefix with $
sign.
users ; // Using stored procedureusers ;
findAndModify
get object properties to search, find the equivalents and modify them(extend
operation).
Usage: users.findAndModify(object, extend)
Aliases: update
Returns: Array
Note: if you want support atomic-transactions(i.e: do things concurrently, e.g: distributed system),
you need use this method prefix with $
sign.
users ; // Push 'a' and 'b' to `list` field(do it concurrently)'a' 'b';
findOneAndModify
get object properties and modify(extend
operation) the first matching.
Usage: users.findOneAndModify(object, extend)
Aliases: updateOne
Returns: Object
Note: if you want support atomic-transactions(i.e: do things concurrently, e.g: distributed system),
you need use this method prefix with $
sign.
users ; // Using stored procedureusers ;
findOrCreate
get object properties, search for document, if it not exist create one.
Usage: users.findOrCreate(object)
Returns: Object
Note: if you want support atomic-transactions(i.e: do things concurrently, e.g: distributed system),
you need use this method prefix with $
sign.
users ; // Using stored procedureusers ;
Queries
Operators
- Logical & Conjunctive:
$or
OR$and
AND$not
NOT$nor
NOT(... OR ...)
- Comparison:
$gt
>$gte
>=$lt
<$lte
<=$ne
<> or !=
- UDF:
$in
likeArray.prototype.some(...)
$all
likeArray.prototype.every(...)
$type
typeof value
$regex
new RegExp(...).test(value)
$size
testarray.length
Examples
users// ... r WHERE r.a=1 AND r.b=2 AND r.c="3" users// ... r WHERE ((r.a=2 AND r.b=3) OR r.c=3) users// ... r WHERE NOT(r.a=1 AND r.b=2 AND r.c=3) users// ... r WHERE NOT(r.a=1 OR r.b=3) users// ... r WHERE NOT((r.a=1 AND r.b=1) OR r.c=3) users// ... r WHERE NOT(r.name > 3 AND r.age=12) users// ... r WHERE NOT(r.name <> "bar") users// ... r WHERE r.name <> "Ariel" OR r.age <= 26 OR (r.isAdmin <> false AND r.isUser <> false) users// ... r WHERE inUDF(r.coins, 2) users// ... r WHERE NOT(typeUDF(r.age, "number"))
Operations
When using one of the update operations(e.g: .update()
, .findAndModify()
, etc...), you could use the build-in prototype
functions(based on the type) prefixing with $
sign.
Usage: users.update({ ... }, { keyName: { $method: value } })
Note: value could be single or array of arguments.
// Find all, and push 2 to `arr` fieldusers; // Suffix all users `name` with #users; // Trim the name from `foo` to `o`users;
Schema
Manage your documents with schema.
fields:
type
- required
- used for type comparing, (e.g:
String
,Boolean
,Number
, etc..).
default
- optional
- value fallback
regex
- optional
- regex validation, (e.g: email validation -
/^[a-zA-Z0-9@:%_\+.~#?&//=|/d]{10,}$/
).
error
- optional
- return message to fields that fail in the validation phase(
regex
/type
). see: example
expose
- optional
expose
by default istrue
, unless you set it tofalse
, it's means that all thefind
operations returns the documents without exposing this fields. see: example
Example using schema:
schema: model.js
moduleexports = /** * @field name * @default no default value */ name: type: String 'default': '' /** * @field email * @default no default value * @regex email, min-length = 10 */ email: type: String 'default': '' regex: /^[a-zA-Z0-9@:%_\+.~#?&//=|/d]{10,}$/ error: '`email` must be type string, valid email address, and least 10 chars' expose: true /** * @field password * @default no default value * @regex password */ password: type: String 'default': '' regex: /^.*.*$/ error: '`password` must be type string, contain 8 chars and at least one number, ' + 'one letter and one unique character such as !#$%&? "' expose: false /** * @field isAdmin * @default false */ isAdmin: type: Boolean 'default': false ;
using schema(model.js
)
var DoQmentDB = ; var model = ; // Get model/schemavar connection = new // Create DocumentDB connectionDocumentClientCONFIGHOST CONFIGOPTIONS; var db = connection CONFIGDB; // Create DBManager 'test'var users = db; // Create CollectionManager 'users'users; // Using schema users ; /* [Error: `email` must be type string, valid email address, and least 10 chars ] */ users ;/* [Error: `email` must be type string, valid email address, and least 10 chars ] */ users ;/* { name: 'Ariel', email: 'a8m@gm.com', password: 'Ar2!as_s', id: '2eb7...c0', ... } */users ;/* Get all documents but without exposing fields(i.e: omit `password` field) */
see: How to architect your models
Middleware
Middleware/Hooks are executed at the document level(create
/save
/insert
, update
, remove/delete
).
There are two types of middleware, pre and post.
pre
Usage: users.pre(operation, callback)
Note: pre
middleware are executed one after another, when each middleware calls next.
Example:
users; // Do something asyncusers;// ##Note: the order is importatnt, this example order:// `createdAt()`, `updatedAT()`, `hash/bcrypt()`, and then the `.create` operation will called
post
Usage: users.post(operation, callback)
Note: post
middleware are executed in parallel.
Example:
users;
Atomic Transactions
Since v0.2.6 DoQmentDB supports atomic-transactions using a built-in sporcs(i.e: stored procedures) to handle concurrently well.
Note: To perform some operation this way, you should prefix it with $
.
Read More: DocumentDB - Atomic Transactions
// Lets take some example of `consuming` from two differents// Service-Bus queues and update the same `model`/`document`//// Note: This also could happen in a distributed system, when two operations happens in parallel // We have a `stores` collection that holds the `sales` and the `users`// fields per `store`(a Document)// We are using the `atomic` version of `update`, because we don't want to lose datasbs; sbs;
Examples
- Koa DocumentDB Example - A users CRUD application using Koa and DocumentDB.
- Express DocumentDB Example - Express application using DocumentDB.
Changelog
0.2.9
- Schema Fix- issue #26
0.2.8
- Add aliases:
updateOne
and$updateOne
(the conccurent one) - refactor the built-in stored procedure(
findAndModify
)
0.2.6
Since 0.2.6 DoQmentDB support atomic transactions using DocumentDB stored procedures
.
Methods that support:
update
/findAndModify
findOneAndModify
findOrCreate
findAndRemove
findOneAndRemove
If you want to use one of this methods, you should use them prefix with $
sign.
// Push 'a' and 'b' to `list` field(do it concurrently)'a' 'b';