Mongoise -- Mongo Promise library
Pronounce as "mong-oise," although "mongo-iss" may make more sense.
This library creates a very simple promise wrapper around the default Node Mongo client allowing it to be used with promise-like syntax.
Mongoise implements its own Deferred
and Promise
objects that do not adhere to the
Promises/A+ specification.
Instead, Mongoise has an implementation that is similar
to the jQuery
Deferred Object.
Mongoise exposes two objects: the Deferred
object, which
can be used for simple promises implementation, and the
Mongoise
object itself. Mongoise allows you to access
MongoDB collection and cursor methods and use their return
values as promises.
The Deferred
object is not very feature complete.
A much more complete promises library is the
q library, which is also
available as an npm package. If you want to do anything
more sophisticated than simple done/fail callbacks and
chaining, you should use a separate API. Using
Deferred
directly is generally not needed either.
Usage
Normal Usage
Use mongoise to connect to the DB via the connect
method.
This method returns a promise, and you can continue
from there.
var mongoisePackage = mongoise = promise = mongoise; promise;promise; // You can also chain callbacks// even directly to the `.connect` callpromise;
Once mongoise is connected, you can use the collection API to do normal MongoDB operations using promises.
var users = mongoise;users;
If you already have a MongoClient
connection available,
you can pass this as an argument to the Mongoise
constructor and skip the connect
step.
MongoClient;
Calling MongoDB Methods
Mongoise
implements all methods according to the
Node MongoDB Collection
and Cursor
APIs. You can call these methods identically to how you
would call them with mongodb
.
However, the Mongoise
objects automatically add
the callback to create the promise that you can chain
to. This means that you should omit the callback
argument from all MongoDB method calls and instead rely
on the promise API.
In case you actually need to communicate using MongoClient
directly, you can create your own or simply access the
dbc
property on the Mongoise
object. It is an unwrapped
MongoClient instance.
Deferred
Using Mongoise The mongoise package exposes a Deferred
object that you
can use separately. A Deferred
instance has reject
and resolve
methods as well as a promise
property.
Most calls to Mongoise collection/cursor instances return
a promise
instance -- specifically methods that take
callbacks. The resolution/rejection of the Deferred
is handled internally.
// Using a deferred yourselfvar dfd = dfdpromise; if some_success_condition // You can pass multiple arguments to the callback dfdelse dfd;
Chaining
You can chain success and failure callbacks. Success and failure callbacks have no particular meaning when chained to one another -- they are resolved separately. When a success callback is chained to a success callback (or a failure callback is chained to a failure callback), the argument for the chained callback is the return value of the callback to which it is chained.
If that sounds confusing, here is an example:
var dfd = promise = dfdpromise;promise ; // Arguments passed to *first* method in the chaindfd;
API
Mongoise exposes its own API for MongoClient connection, the MongoClient itself, a Collection API that uses mongoise promises, and a Deferred API.
Promise
The Promise
API is critical, and the functional part of
Mongoise. A Promise
instance is returned from most
MongoDB methods that take callbacks.
.done
The done
method adds a success callback to the Promise.
When its Deferred
is resolved (i.e. the intended action
completes successfully), any callbacks applied to the
promise via done
are fired.
Any callbacks added with fail
are not fired.
.fail
Functionally the same as done
, but used to add error
callbacks. When the Promise's Deferred
is rejected
(i.e. the intended action completes unsuccessfully),
any callbacks applied to the promise via fail
are fired.
Any callbacks added with done
are not fired.
Chaining
The .fail
and .done
methods both return a promise.
Although this is technically a separate promise, it will
be fulfilled at the same time as its creator's deferred
is fulfilled.
This means that if you chain .done
to .fail
and the
Deferred is resolved, the .done
callback will still
fire even though the .fail
callback will not.
var dfd = ; promise = dfdpromise; // It is okay to resolve the deferred *before*// the callback methods are attached.// They will still firedfd; promise
Mongoise
The Mongoise
has several methods and the dbc
MongoDB
connection property. Only methods intended for external
use are explained.
connect
- Arguments
- connection URL
- Return
Promise
Connect to the MongoDB for the provided URL. This also sets up the Mongoise object for using database-reliant methods.
collection
- Arguments
- collection name
- Return
Collection
Collection
The Collection
instance exposes all of the methods of the
Node MongoDB Collection
and can be used almost identically.
Note: You should leave off the callback argument
when calling a method on the collection instance. Most
methods return a promise
that you can call done
and
fail
on instead.
A comparison of the MongoDB route vs. Mongoise would be:
mongoDbCollection; mongoiseCollection
The above will function identically.
Since Collection
simply wraps the MongoDB methods, you
can use all other arguments as you would. Only the
callback handling is changed.
.find
and .findOne
The .find
and .findOne
methods return a Cursor
instead of a promise. These methods are different, and
you can safely pass callbacks to them.
.aggregate
The MongoDB .aggregate
method allows you to create a
cursor based on the arguments you provide. If you do
create one, Mongoise's Collection
will return a Cursor
Otherwise, it will return a Promise
that you can use
normally.
Cursor
Some MongoDB methods return a cursor object. The
Mongoise Cursor
instance is simply a wrapper for the
Node MongoDB Cursor,
and you can call identical methods.
As with Collection
, you should leave off the callback
argument for most methods and instead chain
success/failure callbacks to the promise that is returned.
.rewind
, .stream
, .isClosed
These methods do not require a callback and return their
values instantly. If you call them on Cursor
, it will
return the intended value and not a promise object.
Deferred
.resolve
, .reject
These function more or less identically. When you call
.resolve
, all success callbacks chained to the Deferred's
promise will be fired. If you call reject
, the same
occurs for the failure callbacks.
Once a Deferred
has been rejected or resolved, you cannot
reject or resolve it again. Attempting to do so will
throw an error.
You can pass multiple arguments to .resolve
and .reject
.
The arguments for the first callback in the chain will
will be these same arguments.
TODO
- Implement
.then
- In general, follow popular promise implementations closer
- Add more tests, especially for methods with weird
behavior like
.find
and.aggregate