Comparing version
@@ -1,12 +0,12 @@ | ||
{ "name": "mongoose" | ||
, "description": "ORM for MongoDB" | ||
, "version": "0.0.5" | ||
, "author": "LearnBoost <dev@learnboost.com>" | ||
, "dependencies": { "mongodb": "0.7.9"} | ||
, "keywords": [ "mongoose", "mongo", "mongodb", "orm", "nosql" ] | ||
, "directories": { "lib": "./lib" } | ||
, "scripts": { "test": "make test" } | ||
, "engines": { "node": ">= 0.1.101" } | ||
, "main": "./mongoose" | ||
, "licenses": [ { "type": "The MIT License", "url": "http://www.opensource.org/licenses/mit-license.php" } ] | ||
{ | ||
"name": "mongoose" | ||
, "description": "Mongoose MongoDB ORM" | ||
, "version": "1.0.0" | ||
, "author": "Guillermo Rauch <guillermo@learnboost.com>" | ||
, "keywords": ["mongodb", "mongoose", "orm", "data", "datastore", "nosql"] | ||
, "dependencies": {} | ||
, "directories": { "lib": "./lib/mongoose" } | ||
, "scripts": { "test": "make test" } | ||
, "main": "./index.js" | ||
, "engines": { "node": ">= 0.2.0" } | ||
} |
494
README.md
@@ -1,397 +0,249 @@ | ||
Mongoose: MongoDB ODM/ORM | ||
========================= | ||
Mongoose 1.0 | ||
============ | ||
The goal of Mongoose is to provide an extremely simple interface for MongoDB. | ||
## What's Mongoose? | ||
## Features | ||
Mongoose is a MongoDB object modeling tool designed to work in an asychronous | ||
environment. | ||
- Reduces the burden of dealing with nested callback from async operations. | ||
- Provides a simple yet rich API. | ||
- Ability to model your data with custom interfaces. | ||
- Allows for complex business logic in an async way (see `Promises`). | ||
Defining a model is as easy as: | ||
## Installation | ||
var Comments = new Schema({ | ||
title : String | ||
, body : String | ||
, date : Date | ||
}); | ||
### As a submodule of your project (recommended) | ||
var BlogPost = new Schema({ | ||
author : ObjectId | ||
, title : String | ||
, body : String | ||
, date : Date | ||
, comments : [Comments] | ||
, meta : { | ||
votes : Number | ||
, favs : Number | ||
} | ||
}); | ||
git submodule add git://github.com/LearnBoost/mongoose.git {path/to/mongoose} | ||
git submodule update --init --recursive | ||
Example paths: `support/mongoose`, `vendor/mongoose`. | ||
### Cloning the repository (mainly for making changes to mongoose) | ||
git clone git://github.com/LearnBoost/mongoose.git --recursive | ||
cd mongoose | ||
### With npm | ||
mongoose.model('BlogPost', BlogPost); | ||
npm install http://github.com/learnboost/mongoose/tree/0.0.2 | ||
### With Kiwi | ||
## Connecting to MongoDB | ||
kiwi install mongoose | ||
## How to use | ||
First, we need to define a connection. If your app uses only one database, you | ||
should use `mongose.connect`. If you need to create additional connections, use | ||
`mongoose.createConnection`. | ||
### Setup | ||
Both `connect` and `createConnection` take a `mongodb://` URI, or the parameters | ||
`host, database, port`. | ||
Simply require Mongoose: | ||
var mongoose = require('mongoose'); | ||
require.paths.unshift('vendor/mongoose'); | ||
var mongoose = require('mongoose').Mongoose; | ||
mongoose.connect('mongodb://localhost/my_database'); | ||
### Defining a model | ||
Once connected, the `open` event is fired on the `Connection` instance. If | ||
you're using `mongoose.connect`, the `Connection` is `mongoose.connection`. | ||
Otherwise, `mongoose.createConnection` return value is a `Connection`. | ||
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 | ||
**Important!** Mongoose buffers all the commands until it's connected to the | ||
database. This means that you don't have to wait until it connects to MongoDB | ||
in order to define models, run queries, etc. | ||
Models are pseudo-classes that depend on an active connection. To connect: | ||
## Defining a Model | ||
var db = mongoose.connect('mongodb://localhost/db'); | ||
To get a model: | ||
var User = db.model('User'); | ||
To create a new instance (document) | ||
Models are defined through the `Schema` interface. | ||
var u = new User(); | ||
u.name = 'John'; | ||
u.save(function(){ | ||
sys.puts('Saved!'); | ||
}); | ||
To fetch some stuff | ||
var Schema = mongoose.Schema | ||
, ObjectId = Schema.ObjectId; | ||
User.find({ name: 'john' }).all(function(array){ | ||
var BlogPost = new Schema({ | ||
author : ObjectId | ||
, title : String | ||
, body : String | ||
, date : Date | ||
}); | ||
### Operating on embedded objects | ||
Aside from defining the structure of your documents and the types of data you're | ||
storing, a Schema handles the definition of: | ||
Embedded objects are hydrated like model instances. Assume a MongoDB document like this stored in a variable `user` | ||
* Validators (async and sync) | ||
* Defaults | ||
* Getters | ||
* Setters | ||
* Indexes | ||
* Middleware | ||
* Methods definition | ||
* Statics definition | ||
* Plugins | ||
{ | ||
name: 'John', | ||
blogposts: [ | ||
{ | ||
title: 'Hi', | ||
body: 'Hi there' | ||
} | ||
] | ||
} | ||
To add a blogpost: | ||
The following example shows some of these features: | ||
user.blogposts.push({ title: 'New post', body: 'The body' }); | ||
user.save(); | ||
var Comment = new Schema({ | ||
name : { type: String, default: 'hahaha' } | ||
, age : { type: Number, min: 18, index: true } | ||
, bio : { type: String, match: /[a-z]/ } | ||
, date : { type: Date, default: Date.now } | ||
}); | ||
To remove an existing one: | ||
// a setter | ||
Comment.path('name').set(function (v) { | ||
return v.capitalize(); | ||
}); | ||
user.blogposts[0] = null; | ||
user.save(); | ||
// middleware | ||
Comment.pre('save', function (next) { | ||
notify(this.get('email')); | ||
next(); | ||
}); | ||
## API | ||
Take a look at the example in `examples/schema.js` for an end-to-end example of | ||
(almost) all the functionality available. | ||
### mongoose | ||
## Accessing a Model | ||
#### 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()`) | ||
### Model | ||
Once we define a model through `mongoose.model('ModelName', mySchema)`, we can | ||
access it through the same function | ||
These are methods and properties that all *model instances* already include: | ||
var myModel = mongoose.model('ModelName'); | ||
#### Properties | ||
We can then instantiate it, and save it: | ||
- **isNew** | ||
Whether the instance exists as a document or the db (*false*), or hasn't been saved down before (*true*) | ||
var instance = new myModel(); | ||
myModel.my.key = 'hello'; | ||
myModel.save(function (err) { | ||
// | ||
}); | ||
#### Methods | ||
Or we can find documents from the same collection | ||
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. | ||
myModel.find({}, function (err, docs) { | ||
// docs.forEach | ||
}); | ||
- **save(fn)** | ||
Saves down the document and fires the callback. | ||
- **remove(fn)** | ||
Removes the document and fires the callback. | ||
### Model (static) | ||
You can also `findOne`, `findById`, `update`, etc. For more details check out | ||
the API docs. | ||
These are the methods that can be accessed statically, and affect the collection as a whole. | ||
## Embedded Documents | ||
- **find(props, subset, hydrate)** | ||
In the first example snippet, we defined a key in the Schema that looks like: | ||
Returns an instance of QueryWriter | ||
comments: [Comments] | ||
- *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. | ||
Where `Comments` is a `Schema` we created. This means that creating embedded | ||
documents is as simple as: | ||
- **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)** | ||
// retrieve my model | ||
var BlogPost = mongoose.model('BlogPost'); | ||
Sets/updates *only* the properties of the passed document for the specified object id | ||
// create a blog post | ||
var post = new BlogPost(); | ||
- *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)** | ||
// create a comment | ||
post.comments.push({ title: 'My comment' }); | ||
Executes the query (and triggers a remove of the matched documents) | ||
post.save(function (err) { | ||
if (!err) console.log('Success!'); | ||
}); | ||
- *where* | ||
Valid where clause. | ||
- *fn* | ||
Optional callback. Called on success. | ||
The same goes for removing them: | ||
### EmbeddedObject | ||
BlogPost.findById(myId, function (err, post) { | ||
if (!err) { | ||
post.comments[0].remove(); | ||
post.save(function (err) { | ||
// do something | ||
}); | ||
} | ||
}); | ||
#### Methods | ||
Embedded documents enjoy all the same features as your models. Defaults, | ||
validators, middleware. Whenever an error occurs, it's bubbled to the `save()` | ||
error callback, so error handling is a snap! | ||
- **remove** | ||
Marks the embeded object for deletion | ||
### QueryWriter | ||
Mongoose interacts with your embedded documents in arrays _atomically_, out of | ||
the box. | ||
QueryWriter allows you to construct queries with very simple syntax. All its methods return the `QueryWriter` instance, which means they're chainable. | ||
## Middleware | ||
#### Methods | ||
Middleware is one of the most exciting features about Mongoose 1.0. Middleware | ||
takes away all the pain of nested callbacks. | ||
##### Executers | ||
Middleware are defined at the Schema level and are applied when the methods | ||
`init` (when a document is initialized with data from MongoDB), `save` (when | ||
a document or embedded document is saved). | ||
These methods execute the query and return a `QueryPromise`. | ||
There's two types of middleware, determined by the signature of the function | ||
you define (ie: the parameters your function accepts): | ||
- **exec** | ||
- Serial | ||
Serial middleware are defined like: | ||
Executes the query. | ||
.pre(method, function (next) { | ||
// ... | ||
}) | ||
- **count** | ||
They're executed one after the other, when each middleware calls `next`. | ||
Executes the query (and triggers a count) | ||
- Parallel | ||
Parallel middleware offer more fine-grained flow control, and are defined | ||
like | ||
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: | ||
.pre(method, function (next, done) { | ||
// ... | ||
}) | ||
User.find({username: 'john'}).all(fn) | ||
and: | ||
User.find({username: 'john'}).exec().all(fn) | ||
Parallel middleware can `next()` immediately, but the final argument will be | ||
called when all the parallel middleware have called `done()`. | ||
##### Modifiers | ||
- **where** | ||
- **sort** | ||
### Error handling | ||
- **limit** | ||
If any middleware calls `next` or `done` with an `Error` instance, the flow is | ||
interrupted, and the error is passed to the function passed as an argument. | ||
- **skip** | ||
For example: | ||
- **snapshot** | ||
schema.pre('save', function (next) { | ||
// something goes wrong | ||
next(new Error('something went wrong')); | ||
}); | ||
- **group** | ||
// later... | ||
### QueryPromise | ||
A promise is a special object that acts as a `queue` if MongoDB has not resulted the results, and executes the methods you call on it once the results are available. | ||
For example | ||
User.find({ age: { '$gt': 5 } }).first(function(result){ | ||
// gets first result | ||
}).last(function(result){ | ||
// gets last result | ||
myModel.save(function (err) { | ||
// err can come from a middleware | ||
}); | ||
#### Methods | ||
## API docs | ||
- **stash(fn)** | ||
You can find the [Dox](http://github.com/visionmedia/dox) generated API docs at | ||
http://mongoosejs.com. | ||
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. | ||
## Contributing to Mongoose | ||
- **complete(result)** | ||
### Cloning the repository | ||
Completes the promise. The result parameter is optional. It's either null or an array of documents. (internal use) | ||
Make a fork of `mongoose`, then clone it in your computer. The `master` branch | ||
contains the current stable release, and the `develop` branch the next upcoming | ||
major release. | ||
##### Queueable Methods | ||
If `master` is at `1.0`, `develop` will contain the upcoming `1.1` (or `2.0` if | ||
the `1` branch is nearing its completion). | ||
You can call all of these in a row, but the callbacks will only trigger when `complete is called` | ||
### Guidelines | ||
- **all(fn)** | ||
- Please write inline documentation for new methods or class members. | ||
- Please write tests and make sure your tests pass. | ||
- Before starting to write code, look for existing tickets or create one for | ||
your specifc issue (unless you're addressing something that's clearly broken). | ||
That way you avoid working on something that might not be of interest or that | ||
has been addressed already in a different branch. | ||
Fires with all the results as an array, or an empty array. | ||
- **get(fn)** | ||
Synonym to `all` | ||
- **last(fn)** | ||
Fires with the last document or *null* | ||
- **first(fn)** | ||
Fires with the first document of the resulset or *null* if no documents are returned | ||
- **one(fn)** | ||
Synonym to `first` | ||
## Credits | ||
Nathan White <nathan@learnboost.com> | ||
- Guillermo Rauch - guillermo@learnboost.com - [Guille](http://github.com/guille) | ||
- Nathan White - [nw](http://github.com/nw/) | ||
- Brian Noguchi - [bnoguchi](https://github.com/bnoguchi) | ||
Guillermo Rauch <guillermo@learnboost.com> | ||
## License | ||
## License | ||
(The MIT License) | ||
Copyright (c) 2010 LearnBoost <dev@learnboost.com> | ||
@@ -398,0 +250,0 @@ |
Sorry, the diff of this file is not supported yet
Install scripts
Supply chain riskInstall scripts are run when the package is installed. The majority of malware in npm is hidden in install scripts.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 2 instances in 1 package
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 4 instances in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Unidentified License
License(Experimental) Something that seems like a license was found, but its contents could not be matched with a known license.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Uses eval
Supply chain riskPackage uses dynamic code execution (e.g., eval()), which is a dangerous practice. This can prevent the code from running in certain environments and increases the risk that the code may contain exploits or malicious behavior.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
1365507
1769.66%0
-100%196
988.89%25456
1255.48%1
-50%1
Infinity%269
-35.49%2
100%70
3400%9
350%- Removed