Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

merged in changes, thanks iriefish, cginzel, eegg

  • Loading branch information...
commit b2f403eb6800df80103cec181576959db39ad007 2 parents 59b0709 + 5c5476b
@nw nw authored
View
408 README.md
@@ -29,164 +29,165 @@ The goal of Mongoose is to provide a extremely simple interface for MongoDB.
Simply require Mongoose:
- var mongoose = require('mongoose').Mongoose;
+ require.paths.unshift('vendor/mongoose');
+ var mongoose = require('mongoose').Mongoose;
### Defining a model
- mongoose.model('User', {
-
- properties: ['first', 'last', 'age', 'updated_at'],
-
- cast: {
- age: Number,
- 'nested.path': String
- },
-
- indexes: ['first'],
-
- setters: {
- first: function(v){
- return this.v.capitalize();
- }
- },
-
- getters: {
- full_name: function(){
- return this.first + ' ' + this.last
- }
- },
-
- methods: {
- save: function(fn){
- this.updated_at = new Date();
- this.__super__(fn);
- }
- },
-
- static: {
- findOldPeople: function(){
- return this.find({age: { '$gt': 70 }});
- }
- }
-
- });
-
+ mongoose.model('User', {
+
+ properties: ['first', 'last', 'age', 'updated_at'],
+
+ cast: {
+ age: Number,
+ 'nested.path': String
+ },
+
+ indexes: ['first'],
+
+ setters: {
+ first: function(v){
+ return this.v.capitalize();
+ }
+ },
+
+ getters: {
+ full_name: function(){
+ return this.first + ' ' + this.last
+ }
+ },
+
+ methods: {
+ save: function(fn){
+ this.updated_at = new Date();
+ this.__super__(fn);
+ }
+ },
+
+ static: {
+ findOldPeople: function(){
+ return this.find({age: { '$gt': 70 }});
+ }
+ }
+
+ });
+
### Getting a model
Models are pseudo-classes that depend on an active connection. To connect:
- var db = mongoose.connect('mongodb://localhost/db');
-
+ var db = mongoose.connect('mongodb://localhost/db');
+
To get a model:
-
- var User = db.model('User');
-
+
+ var User = db.model('User');
+
To create a new instance (document)
- var u = new User();
- u.name = 'John';
- u.save(function(){
- sys.puts('Saved!');
- });
-
+ var u = new User();
+ u.name = 'John';
+ u.save(function(){
+ sys.puts('Saved!');
+ });
+
To fetch some stuff
- User.find({ name: 'john' }).all(function(array){
-
- });
+ User.find({ name: 'john' }).all(function(array){
+
+ });
### Operating on embedded objects
Embedded objects are hydrated like model instances. Assume a MongoDB document like this stored in a variable `user`
- {
- name: 'John',
- blogposts: [
- {
- title: 'Hi',
- body: 'Hi there'
- }
- ]
- }
-
+ {
+ name: 'John',
+ blogposts: [
+ {
+ title: 'Hi',
+ body: 'Hi there'
+ }
+ ]
+ }
+
To add a blogpost:
- user.blogposts.push({ title: 'New post', body: 'The body' });
- user.save();
+ user.blogposts.push({ title: 'New post', body: 'The body' });
+ user.save();
To remove an existing one:
- user.blogposts[0] = null;
- user.save();
+ user.blogposts[0] = null;
+ user.save();
## API
### mongoose
#### Methods
-
+
- **model(name, definition)**
-
- - *definition* determines how the class will be constructed. It's composed of the following keys. All of them are optional:
-
- - *collection*
-
- Optionally, the MongoDB collection name. Defaults to the model name in lowercase and plural. Does not need to be created in advance.
-
- - *properties*
-
- Defines the properties for how you structure the model.
-
- To define simple keys:
-
- properties: [ 'name', 'last' ]
-
- To define arrays:
-
- properties: [ 'name', {'tags': []} ]
-
- To define nested objects:
-
- properties: [ 'name', {contact: ['email', 'phone', ...]} ]
-
- To define array of embedded objects:
-
- properties: [ 'name', {blogposts: [['title', 'body', ...]]} ]
-
- `_id` is added automatically for all models.
-
- - *getters*
-
- Defines getters (can be nested). If the getter matches an existing property, the existing value will be passed as the first argument.
-
- - *setters*
-
- Defines setters (can be nested). If the setter matches an existing property, the return value will be set.
-
- - *cast*
-
- Defines type casting. By default, all properties beginning with `_` are cast to `ObjectID`. (note: Casting an Array will cast all items in the Array. Currently, Arrays cast when 'save' is called.)
-
- - *indexes*
-
- An array of indexes.
-
- Simple indexes: ['name', 'last']
-
- Compound indexes: [{ name: 1, last: 1 }, ...]
-
- Indexes with options: ['simple', [{ name: 1 }, {unique: true}]]
-
- Notice that the objects that you pass are equivalent to those that you would pass to ensureIndex in MongoDB.
-
- - *methods*
-
- Methods that are added to the prototype of the model, or methods that override existing ones. For example `save` (you can call `__super__` to access the parent)
-
- - *static*
-
- Static methods that are not instance-dependent (eg: `findByAge()`)
-
+
+ - *definition* determines how the class will be constructed. It's composed of the following keys. All of them are optional:
+
+ - *collection*
+
+ Optionally, the MongoDB collection name. Defaults to the model name in lowercase and plural. Does not need to be created in advance.
+
+ - *properties*
+
+ Defines the properties for how you structure the model.
+
+ To define simple keys:
+
+ properties: [ 'name', 'last' ]
+
+ To define arrays:
+
+ properties: [ 'name', {'tags': []} ]
+
+ To define nested objects:
+
+ properties: [ 'name', {contact: ['email', 'phone', ...]} ]
+
+ To define array of embedded objects:
+
+ properties: [ 'name', {blogposts: [['title', 'body', ...]]} ]
+
+ `_id` is added automatically for all models.
+
+ - *getters*
+
+ Defines getters (can be nested). If the getter matches an existing property, the existing value will be passed as the first argument.
+
+ - *setters*
+
+ Defines setters (can be nested). If the setter matches an existing property, the return value will be set.
+
+ - *cast*
+
+ Defines type casting. By default, all properties beginning with `_` are cast to `ObjectID`. (note: Casting an Array will cast all items in the Array. Currently, Arrays cast when 'save' is called.)
+
+ - *indexes*
+
+ An array of indexes.
+
+ Simple indexes: ['name', 'last']
+
+ Compound indexes: [{ name: 1, last: 1 }, ...]
+
+ Indexes with options: ['simple', [{ name: 1 }, {unique: true}]]
+
+ Notice that the objects that you pass are equivalent to those that you would pass to ensureIndex in MongoDB.
+
+ - *methods*
+
+ Methods that are added to the prototype of the model, or methods that override existing ones. For example `save` (you can call `__super__` to access the parent)
+
+ - *static*
+
+ Static methods that are not instance-dependent (eg: `findByAge()`)
+
### Model
These are methods and properties that all *model instances* already include:
@@ -194,55 +195,100 @@ These are methods and properties that all *model instances* already include:
#### Properties
- **isNew**
-
- Whether the instance exists as a document or the db (*false*), or hasn't been saved down before (*true*)
+
+ Whether the instance exists as a document or the db (*false*), or hasn't been saved down before (*true*)
#### Methods
Note: if you override any of these by including them in the `methods` object of the model definition, the method is inherited and you can call __super__ to access the parent.
- **save(fn)**
-
- Saves down the document and fires the callback.
-
+
+ Saves down the document and fires the callback.
+
- **remove(fn)**
-
- Removes the document and fires the callback.
-
+
+ Removes the document and fires the callback.
+
### Model (static)
These are the methods that can be accessed statically, and affect the collection as a whole.
- **find(props, subset, hydrate)**
- Returns an instance of QueryWriter
-
- - *props*
-
- Optional, calls the QueryWriter `where` on each key/value. `find({username: 'john'})` is equivalent to:
-
- model.find().where('username', 'john');
-
- - *subset*
-
- Optional, a subset of fields to retrieve. More information on [MongoDB Docs](http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-RetrievingaSubsetofFields)
-
- - *hydrate*
-
- Possible values:
-
- - `true`. Returns a model instance (default)
- - `null`. Returns a plain object that is augmented to match the missing properties defined in the model.
- - `false`. Returns the object as it's retrieved from MongoDB.
+ Returns an instance of QueryWriter
+
+ - *props*
+
+ Optional, calls the QueryWriter `where` on each key/value. `find({username: 'john'})` is equivalent to:
+
+ model.find().where('username', 'john');
+
+ - *subset*
+
+ Optional, a subset of fields to retrieve. More information on [MongoDB Docs](http://www.mongodb.org/display/DOCS/Advanced+Queries#AdvancedQueries-RetrievingaSubsetofFields)
+
+ - *hydrate*
+
+ Possible values:
+
+ - `true`. Returns a model instance (default)
+ - `null`. Returns a plain object that is augmented to match the missing properties defined in the model.
+ - `false`. Returns the object as it's retrieved from MongoDB.
+
+
+- **findById(id, fn, hydrate)**
+
+ Returns an instance of QueryWriter
+
+ - *id*
+
+ Document id (hex or string allowed)
+
+ - *fn*
+
+ Optional callback. Called on success.
+
+ - *hydrate*
+
+ Same as above
+
+- **update(id, doc, fn)**
+
+ Sets/updates *only* the properties of the passed document for the specified object id
+
+ - *id*
+
+ Document id (hex or string allowed)
+
+ - *fn (doc)*
+
+ Optional callback. Called on Success. Doc paramter will contain the hyrdrated document from the DB after the update.
+
+ - *hydrate*
+
+ Same as above
+
+- **remove(where, fn)**
+
+ Executes the query (and triggers a remove of the matched documents)
+
+ - *where*
+
+ Valid where clause.
+
+ - *fn*
+
+ Optional callback. Called on success.
### EmbeddedObject
#### Methods
- **remove**
-
- Marks the embeded object for deletion
-
+
+ Marks the embeded object for deletion
+
### QueryWriter
QueryWriter allows you to construct queries with very simple syntax. All its methods return the `QueryWriter` instance, which means they're chainable.
@@ -255,24 +301,24 @@ These methods execute the query and return a `QueryPromise`.
- **exec**
- Executes the query.
+ Executes the query.
- **count**
- Executes the query (and triggers a count)
+ Executes the query (and triggers a count)
- In addition, for the sake of simplicity, all the promise methods (see "Queueable methods") are mirrored in the QueryWriter and trigger `.exec()`. Then, the following two are equivalent:
+ In addition, for the sake of simplicity, all the promise methods (see "Queueable methods") are mirrored in the QueryWriter and trigger `.exec()`. Then, the following two are equivalent:
- User.find({username: 'john'}).all(fn)
-
- and:
-
- User.find({username: 'john'}).exec().all(fn)
+ User.find({username: 'john'}).all(fn)
+
+ and:
+
+ User.find({username: 'john'}).exec().all(fn)
##### Modifiers
-
+
- **where**
-
+
- **sort**
- **limit**
@@ -289,21 +335,21 @@ A promise is a special object that acts as a `queue` if MongoDB has not resulted
For example
- User.find({ age: { '$gt': 5 } }).first(function(result){
- // gets first result
- }).last(function(result){
- // gets last result
- });
+ User.find({ age: { '$gt': 5 } }).first(function(result){
+ // gets first result
+ }).last(function(result){
+ // gets last result
+ });
#### Methods
- **stash(fn)**
- Stashes all the current queued methods, which will be called when `complete` is called. Methods that are queued **after** stash is called will only fire after `complete` is called again.
+ Stashes all the current queued methods, which will be called when `complete` is called. Methods that are queued **after** stash is called will only fire after `complete` is called again.
- **complete(result)**
- Completes the promise. The result parameter is optional. It's either null or an array of documents. (internal use)
+ Completes the promise. The result parameter is optional. It's either null or an array of documents. (internal use)
##### Queueable Methods
@@ -311,23 +357,23 @@ You can call all of these in a row, but the callbacks will only trigger when `co
- **all(fn)**
- Fires with all the results as an array, or an empty array.
+ Fires with all the results as an array, or an empty array.
- **get(fn)**
- Synonym to `all`
+ Synonym to `all`
- **last(fn)**
- Fires with the last document or *null*
+ Fires with the last document or *null*
- **first(fn)**
- Fires with the first document of the resulset or *null* if no documents are returned
+ Fires with the first document of the resulset or *null* if no documents are returned
- **one(fn)**
- Synonym to `first`
+ Synonym to `first`
## Credits
View
4 lib/core.js
@@ -75,5 +75,5 @@ Mongoose = this.Mongoose = {
};
-sys.inherits(Mongoose, EventEmitter.prototype);
-EventEmitter.call(Mongoose);
+sys.inherits(Mongoose, EventEmitter);
+EventEmitter.call(Mongoose);
View
3  lib/model.js
@@ -161,12 +161,14 @@ Model = this.Model = Class({
},
findById: function(id, fn, hydrate){
+ id = (id instanceof ObjectID || id.toHexString) ? id : ObjectID.createFromHexString(id);
var writer = this.find({_id: id}, hydrate);
if (fn) return writer.first(fn);
return writer;
},
remove: function(where, fn){
+ var self = this;
this._collection.remove(where || {}, function(err){
if (err) return self._connection._error(err);
fn();
@@ -175,6 +177,7 @@ Model = this.Model = Class({
},
count: function(where, fn){
+ var self = this;
this._collection.count(where || {}, function(err, count){
if (err) return self._connection._error(err);
fn(count);
View
9 tests/integration/model.test.js
@@ -47,6 +47,7 @@ module.exports = {
assert.ok(john._someid.toHexString);
assert.ok(john._someother.toHexString);
assert.equal(john.last, 'Lock');
+ assert.ok(!john.isNew);
db.terminate();
});
});
@@ -61,8 +62,9 @@ module.exports = {
User.find({}, false).all(function(res){
assert.ok(res instanceof Array);
assert.ok(res.length);
- assert.ok(typeof res[0] == 'object')
- assert.ok(! (res[0] instanceof User))
+ assert.ok(typeof res[0] == 'object');
+ assert.ok(! (res[0] instanceof User));
+ assert.ok(!john.isNew);
db.terminate();
});
}
@@ -110,11 +112,13 @@ module.exports = {
User.findById(john._id, function(john){
assert.equal(john.first, 'John');
+ assert.ok(!john.isNew);
complete();
});
User.findById(john._id.toHexString(), function(john){
assert.equal(john.last, 'Lock');
+ assert.ok(!john.isNew);
complete();
});
@@ -136,6 +140,7 @@ module.exports = {
assert.ok(! john.isNew);
User.find({}).all(function(docs){
+ assert.ok(!john.isNew);
assert.ok(docs.length == 1);
john.remove(function(){
Please sign in to comment.
Something went wrong with that request. Please try again.