Comparing version 1.4.6 to 2.0.0
@@ -7,7 +7,9 @@ 'use strict'; | ||
const isGeneratorFn = require('is-generator-fn'); | ||
const pluralize = require('pluralize'); | ||
const compose = require('koa-compose'); | ||
const mongodb = require('mongodb'); | ||
const Promise = require('bluebird'); | ||
const extend = require('class-extend').extend; | ||
const result = require('lodash.result'); | ||
const assign = require('object-assign'); | ||
const clone = require('clone'); | ||
@@ -17,2 +19,3 @@ const get = require('get-value'); | ||
const is = require('is_js'); | ||
const co = require('co'); | ||
@@ -24,2 +27,3 @@ const Query = require('./query'); | ||
/** | ||
@@ -31,97 +35,103 @@ * Mongorito | ||
class Mongorito { | ||
/** | ||
* Connect to a MongoDB database and return connection object | ||
* | ||
* @param {String} urls - connection urls (as arguments) | ||
* @see http://mongodb.github.io/node-mongodb-native/2.0/api/MongoClient.html#.connect | ||
* @api public | ||
*/ | ||
function Mongorito () {} | ||
static connect () { | ||
// parse arguments | ||
let args = Array.prototype.slice.call(arguments); | ||
let urls = []; | ||
let options = {}; | ||
/** | ||
* Connect to a MongoDB database and return connection object | ||
* | ||
* @param {String} urls - connection urls (as arguments) | ||
* @see http://mongodb.github.io/node-mongodb-native/2.0/api/MongoClient.html#.connect | ||
* @api public | ||
*/ | ||
args.forEach(function (arg) { | ||
if (is.string(arg)) { | ||
urls.push(arg); | ||
} | ||
Mongorito.connect = function () { | ||
// parse arguments | ||
let args = Array.prototype.slice.call(arguments); | ||
if (is.object(arg)) { | ||
options = arg; | ||
} | ||
}); | ||
let urls = []; | ||
let options = {}; | ||
urls = urls.map(function (url) { | ||
if (!url.startsWith('mongodb://')) { | ||
url = 'mongodb://' + url; | ||
} | ||
args.forEach(function (arg) { | ||
if (is.string(arg)) { | ||
urls.push(arg); | ||
} | ||
return url; | ||
}); | ||
if (is.object(arg)) { | ||
options = arg; | ||
} | ||
}); | ||
let self = this; | ||
urls = urls.map(function (url) { | ||
if (!url.startsWith('mongodb://')) { | ||
url = 'mongodb://' + url; | ||
} | ||
return MongoClient.connect(urls.join(','), options).then(function (db) { | ||
if (!self.db) { | ||
self.db = db; | ||
} | ||
return url; | ||
}); | ||
return db; | ||
}); | ||
} | ||
let self = this; | ||
let connection = MongoClient.connect(urls.join(','), options).then(function (db) { | ||
if (!self.db) { | ||
self.db = db; | ||
} | ||
return db; | ||
}); | ||
/** | ||
* Disconnect from a database | ||
* | ||
* @api public | ||
*/ | ||
static disconnect () { | ||
return this.db.close(); | ||
if (!this._connection) { | ||
this._connection = connection; | ||
} | ||
return connection; | ||
}; | ||
/** | ||
* Alias for .disconnect() | ||
* | ||
* @api public | ||
*/ | ||
static close () { | ||
return Mongorito.disconnect.apply(this, arguments); | ||
} | ||
/** | ||
* Disconnect from a database | ||
* | ||
* @api public | ||
*/ | ||
Mongorito.disconnect = function () { | ||
return this.db.close(); | ||
}; | ||
/** | ||
* Return a co-wrapped monk collection | ||
* | ||
* @api private | ||
*/ | ||
static _collection (db, name) { | ||
let url = db.s.options.url; | ||
let collections = this._collections[url]; | ||
/** | ||
* Alias for .disconnect() | ||
* | ||
* @api public | ||
*/ | ||
if (!collections) { | ||
collections = this._collections[url] = {}; | ||
} | ||
Mongorito.close = function () { | ||
return Mongorito.disconnect.apply(this, arguments); | ||
}; | ||
if (collections[name]) { | ||
return collections[name]; | ||
} | ||
let collection = db.collection(name); | ||
/** | ||
* Return a co-wrapped monk collection | ||
* | ||
* @api private | ||
*/ | ||
collections[name] = collection; | ||
Mongorito._collection = function (db, name) { | ||
let url = db.s.options.url; | ||
let collections = this._collections[url]; | ||
if (!collections) { | ||
collections = this._collections[url] = {}; | ||
} | ||
if (collections[name]) { | ||
return collections[name]; | ||
} | ||
} | ||
let collection = db.collection(name); | ||
collections[name] = collection; | ||
return collections[name]; | ||
}; | ||
/** | ||
@@ -141,6 +151,6 @@ * Cache for collections | ||
function Model (attrs, options) { | ||
this.attributes = clone(attrs || {}); | ||
this.attributes = assign({}, attrs); | ||
this.changed = {}; | ||
this.previous = {}; | ||
this.options = clone(options || {}); | ||
this.options = options || {}; | ||
@@ -178,17 +188,21 @@ // reset hooks | ||
Model.prototype._collection = function () { | ||
if (is.string(this.collection)) { | ||
return Mongorito._collection(this._db(), this.collection); | ||
} | ||
let self = this; | ||
// get collectio name | ||
// from the "collection" property | ||
// or generate the default one | ||
let defaultName = pluralize(this.constructor.name).toLowerCase(); | ||
let name = result(this, 'collection', defaultName); | ||
return this._db().then(function (db) { | ||
if (is.string(self.collection)) { | ||
return Mongorito._collection(db, self.collection); | ||
} | ||
// save collection name | ||
// to avoid the same check in future | ||
this.collection = this.constructor.prototype.collection = name; | ||
// get collectio name | ||
// from the "collection" property | ||
// or generate the default one | ||
let defaultName = pluralize(self.constructor.name).toLowerCase(); | ||
let name = result(self, 'collection', defaultName); | ||
return Mongorito._collection(this._db(), this.collection); | ||
// save collection name | ||
// to avoid the same check in future | ||
self.collection = self.constructor.prototype.collection = name; | ||
return Mongorito._collection(db, self.collection); | ||
}); | ||
}; | ||
@@ -207,3 +221,5 @@ | ||
// or use a default one | ||
return this.db ? this.db() : Mongorito.db; | ||
let db = this.db ? this.db() : Mongorito._connection; | ||
return Promise.resolve(db); | ||
}; | ||
@@ -309,3 +325,3 @@ | ||
Model.prototype.toJSON = function () { | ||
return this.attributes; | ||
return assign({}, this.attributes); | ||
}; | ||
@@ -355,3 +371,3 @@ | ||
// for each item | ||
if (is.array(method)) { | ||
if (Array.isArray(method)) { | ||
let methods = method; | ||
@@ -369,5 +385,17 @@ | ||
if (is.not.function(method)) { | ||
let name = method; | ||
method = this[method]; | ||
if (!method.name) { | ||
method.name = name; | ||
} | ||
} | ||
// if method is a generator function | ||
// convert it to promise | ||
if (isGeneratorFn(method)) { | ||
method = co.wrap(method); | ||
} | ||
// around hooks should be | ||
@@ -442,2 +470,4 @@ // at the end of before:* | ||
Model.prototype._runHooks = function (when, action, options) { | ||
let self = this; | ||
if (!options) { | ||
@@ -458,7 +488,14 @@ options = {}; | ||
hooks = hooks.filter(function (fn) { | ||
return skip.indexOf(fn.name) === -1; | ||
// generator functions are wrapped using co.wrap() | ||
// which hides the real function name, so we need | ||
// to get function name ourselves | ||
let fnName = fn.__generatorFunction__ ? fn.__generatorFunction__.name : fn.name; | ||
return skip.indexOf(fnName) === -1; | ||
}); | ||
} | ||
return compose(hooks).call(this); | ||
return Promise.each(hooks, function (hook) { | ||
return hook.call(self); | ||
}); | ||
}; | ||
@@ -513,3 +550,3 @@ | ||
if (is.array(value)) { | ||
if (Array.isArray(value)) { | ||
value = value.map(function (doc) { | ||
@@ -535,6 +572,6 @@ return doc.get('_id'); | ||
Model.prototype.create = function * (options) { | ||
let collection = this._collection(); | ||
Model.prototype.create = function (options) { | ||
let self = this; | ||
let attrs = this.attributes; | ||
let date = new Date(); | ||
@@ -547,12 +584,18 @@ | ||
yield* this._runHooks('before', 'create', options); | ||
return this._collection() | ||
.tap(function () { | ||
return self._runHooks('before', 'create', options); | ||
}) | ||
.then(function (collection) { | ||
return collection.insert(attrs); | ||
}) | ||
.then(function (inserted) { | ||
let doc = inserted.ops[0]; | ||
let inserted = yield collection.insert(attrs); | ||
let doc = inserted.ops[0]; | ||
this.set('_id', doc._id); | ||
yield* this._runHooks('after', 'create', options); | ||
return this; | ||
self.set('_id', doc._id); | ||
}) | ||
.then(function () { | ||
return self._runHooks('after', 'create', options); | ||
}) | ||
.return(this); | ||
}; | ||
@@ -567,4 +610,5 @@ | ||
Model.prototype.update = function * (options) { | ||
let collection = this._collection(); | ||
Model.prototype.update = function (options) { | ||
let self = this; | ||
let attrs = this.attributes; | ||
@@ -574,7 +618,13 @@ | ||
yield* this._runHooks('before', 'update', options); | ||
yield collection.update({ _id: attrs._id }, attrs); | ||
yield* this._runHooks('after', 'update', options); | ||
return this; | ||
return this._collection() | ||
.tap(function () { | ||
return self._runHooks('before', 'update', options); | ||
}) | ||
.then(function (collection) { | ||
return collection.update({ _id: attrs._id }, attrs); | ||
}) | ||
.then(function () { | ||
return self._runHooks('after', 'update', options); | ||
}) | ||
.return(this); | ||
}; | ||
@@ -589,10 +639,16 @@ | ||
Model.prototype.remove = function * (options) { | ||
let collection = this._collection(); | ||
Model.prototype.remove = function (options) { | ||
let self = this; | ||
yield* this._runHooks('before', 'remove', options); | ||
yield collection.remove({ _id: this.get('_id') }); | ||
yield* this._runHooks('after', 'remove', options); | ||
return this; | ||
return this._collection() | ||
.tap(function () { | ||
return self._runHooks('before', 'remove', options); | ||
}) | ||
.then(function (collection) { | ||
return collection.remove({ _id: self.get('_id') }); | ||
}) | ||
.then(function () { | ||
return self._runHooks('after', 'remove', options); | ||
}) | ||
.return(this); | ||
}; | ||
@@ -609,3 +665,5 @@ | ||
Model.prototype.inc = function * (props, options) { | ||
Model.prototype.inc = function (props, options) { | ||
let self = this; | ||
let id = this.get('_id'); | ||
@@ -617,29 +675,28 @@ | ||
let collection = this._collection(); | ||
return this._collection() | ||
.tap(function () { | ||
return self._runHooks('before', 'update', options); | ||
}) | ||
.then(function (collection) { | ||
return collection.update({ _id: id }, { '$inc': props }); | ||
}) | ||
.then(function () { | ||
// perform increment locally | ||
// to prevent the need to refresh | ||
// the model from a database | ||
Object.keys(props).forEach(function (key) { | ||
// get current value | ||
let value = self.get(key); | ||
yield* this._runHooks('before', 'update', options); | ||
// perform increment | ||
value += props[key]; | ||
yield collection.update({ _id: id }, { | ||
'$inc': props | ||
}); | ||
// perform increment locally | ||
// to prevent the need to refresh | ||
// the model from a database | ||
let self = this; | ||
Object.keys(props).forEach(function (key) { | ||
// get current value | ||
let value = self.get(key); | ||
// perform increment | ||
value += props[key]; | ||
// save | ||
self.set(key, value); | ||
}); | ||
yield* this._runHooks('after', 'update', options); | ||
return this; | ||
// save | ||
self.set(key, value); | ||
}); | ||
}) | ||
.then(function () { | ||
return self._runHooks('after', 'update', options); | ||
}) | ||
.return(this); | ||
}; | ||
@@ -658,3 +715,5 @@ | ||
// use it, otherwise use the default | ||
return this.prototype.db ? this.prototype.db() : Mongorito.db; | ||
let db = this.prototype.db ? this.prototype.db() : Mongorito._connection; | ||
return Promise.resolve(db); | ||
}; | ||
@@ -670,17 +729,21 @@ | ||
Model._collection = function () { | ||
if (is.string(this.prototype.collection)) { | ||
return Mongorito._collection(this._db(), this.prototype.collection); | ||
} | ||
let self = this; | ||
// get collection name | ||
// from the "collection" property | ||
// or generate the default one | ||
let defaultName = pluralize(this.name).toLowerCase(); | ||
let name = result(this.prototype, 'collection', defaultName); | ||
return this._db().then(function (db) { | ||
if (is.string(self.prototype.collection)) { | ||
return Mongorito._collection(db, self.prototype.collection); | ||
} | ||
// save collection name | ||
// to avoid the same check in future | ||
this.prototype.collection = name; | ||
// get collection name | ||
// from the "collection" property | ||
// or generate the default one | ||
let defaultName = pluralize(self.name).toLowerCase(); | ||
let name = result(self.prototype, 'collection', defaultName); | ||
return Mongorito._collection(this._db(), name); | ||
// save collection name | ||
// to avoid the same check in future | ||
self.prototype.collection = name; | ||
return Mongorito._collection(db, name); | ||
}); | ||
}; | ||
@@ -732,6 +795,7 @@ | ||
Model.findOne = function * (query) { | ||
let docs = yield* this.find(query); | ||
return docs[0]; | ||
Model.findOne = function (query) { | ||
return this.find(query) | ||
.then(function (docs) { | ||
return docs[0]; | ||
}); | ||
}; | ||
@@ -772,3 +836,5 @@ | ||
Model.drop = function () { | ||
return this._collection().drop(); | ||
return this._collection().then(function (collection) { | ||
return collection.drop(); | ||
}); | ||
}; | ||
@@ -784,6 +850,8 @@ | ||
Model.index = function * () { | ||
let collection = this._collection(); | ||
Model.index = function () { | ||
let args = Array.prototype.slice.call(arguments); | ||
return yield collection.ensureIndex.apply(collection, arguments); | ||
return this._collection().then(function (collection) { | ||
return collection.ensureIndex.apply(collection, args); | ||
}); | ||
}; | ||
@@ -799,11 +867,16 @@ | ||
Model.indexes = function * () { | ||
let collection = this._collection(); | ||
Model.indexes = function () { | ||
let args = Array.prototype.slice.call(arguments); | ||
let cursor = collection.listIndexes.apply(collection, arguments); | ||
let indexes = yield cursor.toArray(); | ||
return this._collection().then(function (collection) { | ||
let cursor = collection.listIndexes.apply(collection, args); | ||
cursor.close(); | ||
return cursor | ||
.toArray() | ||
.then(function (indexes) { | ||
cursor.close(); | ||
return indexes; | ||
return indexes; | ||
}); | ||
}); | ||
}; | ||
@@ -842,3 +915,2 @@ | ||
let query = new Query(this._collection(), this); | ||
query[method].apply(query, arguments); | ||
@@ -845,0 +917,0 @@ |
@@ -8,5 +8,4 @@ 'use strict'; | ||
const toObjectId = require('../util/to-objectid'); | ||
const Promise = require('bluebird'); | ||
const assign = require('object-assign'); | ||
const each = require('array-generators').forEach; | ||
const map = require('array-generators').map; | ||
const is = require('is_js'); | ||
@@ -111,3 +110,3 @@ | ||
if (is.array(key)) { | ||
if (Array.isArray(key)) { | ||
let fields = key; | ||
@@ -148,3 +147,3 @@ | ||
if (is.array(key)) { | ||
if (Array.isArray(key)) { | ||
let fields = key; | ||
@@ -304,6 +303,10 @@ | ||
Query.prototype.count = function * (query) { | ||
Query.prototype.count = function (query) { | ||
let self = this; | ||
this.where(query); | ||
return yield this.collection.count(this.query); | ||
return this.collection.then(function (collection) { | ||
return collection.count(self.query); | ||
}); | ||
}; | ||
@@ -319,7 +322,8 @@ | ||
Query.prototype.find = function * (query, options) { | ||
Query.prototype.find = function (query, options) { | ||
let Model = this.model; | ||
let self = this; | ||
this.where(query); | ||
let Model = this.model; | ||
// query options | ||
@@ -337,29 +341,36 @@ options = assign({}, this.options, options); | ||
// find | ||
let cursor = this.collection.find(this.query, options); | ||
let docs = yield cursor.toArray(); | ||
return this.collection | ||
.then(function (collection) { | ||
let cursor = collection.find(self.query, options); | ||
// close cursor | ||
cursor.close(); | ||
return cursor | ||
.toArray() | ||
.then(function (docs) { | ||
cursor.close(); | ||
docs = yield map(docs, function * (doc) { | ||
yield each(populate, function * (key) { | ||
let childModel = options.populate[key]; | ||
return docs; | ||
}); | ||
}) | ||
.map(function (doc) { | ||
return Promise.each(populate, function (key) { | ||
let childModel = options.populate[key]; | ||
let value = doc[key]; | ||
let value = doc[key]; | ||
if (Array.isArray(value)) { | ||
value = Promise.map(value, function (id) { | ||
return childModel.findById(id); | ||
}); | ||
} else { | ||
value = childModel.findById(value); | ||
} | ||
if (is.array(value)) { | ||
value = value.map(childModel.findById, childModel); | ||
} else { | ||
value = childModel.findById(value); | ||
} | ||
doc[key] = yield value; | ||
return value.then(function (value) { | ||
doc[key] = value; | ||
}); | ||
}).then(function () { | ||
return new Model(doc, { | ||
populate: options.populate | ||
}); | ||
}); | ||
}); | ||
return new Model(doc, { | ||
populate: options.populate | ||
}); | ||
}); | ||
return docs; | ||
}; | ||
@@ -375,6 +386,7 @@ | ||
Query.prototype.findOne = function * (query) { | ||
let docs = yield this.find(query); | ||
return docs[0]; | ||
Query.prototype.findOne = function (query) { | ||
return this.find(query) | ||
.then(function (docs) { | ||
return docs[0]; | ||
}); | ||
}; | ||
@@ -402,6 +414,10 @@ | ||
Query.prototype.remove = function * (query) { | ||
Query.prototype.remove = function (query) { | ||
let self = this; | ||
this.where(query); | ||
return yield this.collection.remove(this.query, this.options); | ||
return this.collection.then(function (collection) { | ||
return collection.remove(self.query, self.options); | ||
}); | ||
}; | ||
@@ -448,3 +464,3 @@ | ||
Query.prototype[method] = function () { | ||
let args = is.array(arguments[0]) ? arguments[0] : Array.prototype.slice.call(arguments); | ||
let args = Array.isArray(arguments[0]) ? arguments[0] : Array.prototype.slice.call(arguments); | ||
let operator = '$' + method; | ||
@@ -451,0 +467,0 @@ |
{ | ||
"name": "mongorito", | ||
"version": "1.4.6", | ||
"version": "2.0.0", | ||
"description": "ES6 generator-based MongoDB ODM. It rocks.", | ||
"author": "Vadim Demedes <vdemedes@gmail.com>", | ||
"dependencies": { | ||
"array-generators": "^1.1.0", | ||
"bluebird": "^3.3.1", | ||
"class-extend": "^0.1.2", | ||
"clone": "^1.0.2", | ||
"get-value": "^2.0.2", | ||
"co": "^4.6.0", | ||
"get-value": "^2.0.3", | ||
"is-generator-fn": "^1.0.0", | ||
"is_js": "^0.7.4", | ||
"koa-compose": "^2.3.0", | ||
"lodash.result": "^3.1.2", | ||
"lodash.result": "^4.2.0", | ||
"mongodb": "^2.0.48", | ||
@@ -20,10 +21,9 @@ "object-assign": "^4.0.1", | ||
"devDependencies": { | ||
"ava": "^0.8.0", | ||
"ava": "^0.12.0", | ||
"chance": "^0.8.0", | ||
"coveralls": "^2.11.4", | ||
"eslint-config-vdemedes": "*", | ||
"eslint-config-vdemedes": "^1.0.2", | ||
"nyc": "^5.0.0", | ||
"xo": "^0.11.2" | ||
"xo": "^0.12.1" | ||
}, | ||
"main": "index.js", | ||
"files": [ | ||
@@ -35,3 +35,3 @@ "index.js", | ||
"scripts": { | ||
"test": "xo && nyc ava --serial test/test.js", | ||
"test": "xo && nyc ava --serial", | ||
"coveralls": "nyc report --reporter=text-lcov | coveralls" | ||
@@ -52,7 +52,15 @@ }, | ||
"extends": "vdemedes", | ||
"esnext": true, | ||
"env": [ | ||
"node", | ||
"mocha" | ||
] | ||
], | ||
"ignore": [ | ||
"examples/*.js" | ||
], | ||
"rules": { | ||
"prefer-arrow-callback": 0, | ||
"prefer-spread": 0 | ||
} | ||
} | ||
} |
260
Readme.md
# Mongorito | ||
[![Build Status](https://travis-ci.org/vdemedes/mongorito.svg?branch=master)](https://travis-ci.org/vdemedes/mongorito) [![Coverage Status](https://coveralls.io/repos/vdemedes/mongorito/badge.svg?branch=master&service=github)](https://coveralls.io/github/vdemedes/mongorito?branch=master) | ||
[![Build Status](https://travis-ci.org/vdemedes/mongorito.svg?branch=master)](https://travis-ci.org/vdemedes/mongorito) | ||
[![Coverage Status](https://coveralls.io/repos/vdemedes/mongorito/badge.svg?branch=master&service=github)](https://coveralls.io/github/vdemedes/mongorito?branch=master) | ||
Awesome ES6 generator-based MongoDB ODM for Node.js v4.x (or newer). | ||
Just take a look on its pretty models and beautiful API. | ||
Awesome MongoDB ODM for Node.js apps. | ||
Just take a look at its beautiful models and API. | ||
Uses official [mongodb](https://www.npmjs.com/package/mongodb) driver under the hood. | ||
@@ -17,8 +19,31 @@ | ||
## Quick overview | ||
```js | ||
const mongorito = require('mongorito'); | ||
const Model = mongorito.Model; | ||
class Post extends Model { | ||
} | ||
mongorito.connect('localhost/blog'); | ||
let post = new Post({ | ||
title: 'Steve Angello rocks', | ||
author: { | ||
name: 'Emma' | ||
} | ||
}); | ||
post.save(); | ||
// post saved | ||
``` | ||
## Features | ||
- Based on ES6 generators, which means **no callbacks** | ||
- Based on Promises, which means **no callbacks** | ||
- Established API you've already used to | ||
- Hooks (before:save, around:create, after:remove, etc) | ||
- Very simple and easy-to-understand implementation | ||
- Fully covered by tests | ||
@@ -34,56 +59,227 @@ - Using this module results in a beautiful code | ||
**Note**: In order for the following examples to work, you need to use [co](https://github.com/tj/co) to run generators. | ||
## Usage | ||
- [Connection](#connection) | ||
- [Models](#models) | ||
- [Attributes](#attributes) | ||
- [Save & remove](#save--remove) | ||
- [Queries](#queries) | ||
### Connection | ||
*Check out [connection](examples/connection.js) example.* | ||
Here's how to connect to a `blog` database on `localhost`: | ||
```js | ||
const Mongorito = require('mongorito'); | ||
const Model = Mongorito.Model; | ||
await mongorito.connect('localhost/blog'); | ||
``` | ||
// connect to localhost/blog | ||
yield Mongorito.connect('localhost/blog'); | ||
To disconnect, use `mongorito.disconnect()`: | ||
```js | ||
await mongorito.disconnect(); | ||
``` | ||
// define model | ||
### Models | ||
Use classes to define models: | ||
```js | ||
const Model = mongorito.Model; | ||
class Post extends Model { | ||
} | ||
``` | ||
This defines model `Post` with documents in `posts` collection. | ||
To use a custom collection, add `collection()` method, which returns the name of the desired collection: | ||
```js | ||
class Post extends Model { | ||
collection () { | ||
return 'super_cool_posts'; | ||
} | ||
} | ||
``` | ||
Mongorito models can also be defined old-fashioned Backbone way: | ||
// create and save new Post document | ||
```js | ||
const Post = Model.extend({ | ||
collection: 'posts' | ||
}); | ||
``` | ||
**Note**: `collection` property has to be set. | ||
### Attributes | ||
*Check out [attributes](examples/attributes.js) example.* | ||
To create a new instance of a model, simply use `new`: | ||
```js | ||
let post = new Post({ | ||
title: 'Node.js with --harmony rocks!', | ||
body: 'Long post body', | ||
author: { | ||
name: 'John Doe' | ||
} | ||
title: 'Great title', | ||
author: { | ||
name: 'Emma' | ||
} | ||
}); | ||
``` | ||
yield post.save(); | ||
To retrieve a specific attribute (even a nested one): | ||
```js | ||
let title = post.get('title'); | ||
let author = post.get('author.name'); | ||
``` | ||
// update document | ||
post.set('title', 'Post got a new title!'); | ||
post.set('author.name', 'Doe John'); | ||
All attributes can be retrieved at once using either `toJSON()` or `get()`: | ||
yield post.save(); | ||
```js | ||
let attrs = post.toJSON(); | ||
let attrs = post.get(); | ||
``` | ||
// find posts where body equals "Long post body" | ||
let posts = yield Post.where('body', 'Long post body').find(); | ||
Set new values via `set()` method: | ||
// find posts where author's name equals "John Doe" | ||
posts = yield Post.where('author.name', 'John Doe').find(); | ||
```js | ||
post.set('title', 'New title'); | ||
post.set('author.name', 'Rachel'); | ||
``` | ||
// Bonus: find posts where title starts with "Node" | ||
posts = yield Post.where('title', /^node/i).find(); | ||
### Save & Remove | ||
*Check out [manage](examples/manage.js) example.* | ||
Use a `save()` method to create/update (Mongorito handles that for you) a model: | ||
```js | ||
let post = new Post(); | ||
await post.save(); // creates a new post | ||
post.set('title', 'New title'); | ||
await post.save(); // updates an existing post | ||
``` | ||
To remove a model from collection: | ||
## API | ||
```js | ||
await post.remove(); | ||
``` | ||
Check out [Getting Started](http://mongorito.com/guides/getting-started) guide on [http://mongorito.com](http://mongorito.com). | ||
There are more guides available to learn more. | ||
You can also remove all models matching a certain criteria: | ||
```js | ||
await Post.remove({ title: 'New title' }); | ||
``` | ||
### Queries | ||
#### Find all | ||
To fetch all models `find()` or `all()` can be used (they're identical): | ||
```js | ||
Post.find(); | ||
Post.all(); | ||
``` | ||
#### Find one | ||
```js | ||
Post.findOne({ title: 'New title' }); | ||
``` | ||
#### Find by ID | ||
```js | ||
Post.findById('56c9e0922cc9215110ab26dc'); | ||
``` | ||
#### Find where value equals | ||
```js | ||
Post.where('title', 'New title').find(); | ||
Post.where('author.name', 'Emma').find(); | ||
``` | ||
#### Find where value matches a regular expression | ||
```js | ||
Post.where('title', /something/i).find(); | ||
``` | ||
#### Find where attribute exists | ||
```js | ||
Post.exists('title').find(); | ||
``` | ||
#### Find where value is less/greater than | ||
```js | ||
Post.where('comments_number').lt(5).find(); // less than 5 | ||
Post.where('comments_number').lte(5).find(); // less than or equal 5 | ||
Post.where('comments_number').gt(5).find(); // greater than 5 | ||
Post.where('comments_number').gte(5).find(); // greater than or equal 5 | ||
``` | ||
### Find where value is one of | ||
```js | ||
Post.in('comments_number', [4, 8]).find(); | ||
``` | ||
#### Find using OR | ||
Find all models where `title` equals either "First" or "Second": | ||
```js | ||
Post.or({ title: 'First' }, { title: 'Second' }).find(); | ||
``` | ||
#### Limit results | ||
```js | ||
Post.limit(10).find(); | ||
``` | ||
#### Skip results | ||
Skip first N results: | ||
```js | ||
Post.skip(4).find(); | ||
``` | ||
#### Sort results | ||
```js | ||
// descending | ||
Post.sort('comments_number', -1); | ||
// ascending | ||
Post.sort('comments_number', 1); | ||
``` | ||
#### Count results | ||
Count all documents in collection: | ||
```js | ||
Post.count(); | ||
``` | ||
Count all documents matching a certain criteria: | ||
```js | ||
Post.count({ awesome: true }); | ||
``` | ||
## Tests | ||
@@ -90,0 +286,0 @@ |
30214
1083
293
12
+ Addedbluebird@^3.3.1
+ Addedco@^4.6.0
+ Addedis-generator-fn@^1.0.0
+ Addedbluebird@3.7.2(transitive)
+ Addedis-generator-fn@1.0.0(transitive)
+ Addedlodash.result@4.5.2(transitive)
- Removedarray-generators@^1.1.0
- Removedkoa-compose@^2.3.0
- Removedarray-generators@1.1.0(transitive)
- Removedkoa-compose@2.5.1(transitive)
- Removedlodash._baseget@3.7.2(transitive)
- Removedlodash._baseslice@3.0.3(transitive)
- Removedlodash._topath@3.8.1(transitive)
- Removedlodash.isarray@3.0.4(transitive)
- Removedlodash.isfunction@3.0.9(transitive)
- Removedlodash.result@3.1.2(transitive)
Updatedget-value@^2.0.3
Updatedlodash.result@^4.2.0