This commit is contained in:
root
2019-11-28 20:40:02 +00:00
commit 1c78566f5b
2275 changed files with 272351 additions and 0 deletions
+3
View File
@@ -0,0 +1,3 @@
module.exports = {
uri: 'mongodb+srv://lambda_test:a1b2c3@cluster0-xvnqv.mongodb.net/test?retryWrites=true&w=majority'
}
+6
View File
@@ -0,0 +1,6 @@
docs/
bin/
test/triage/
test/model.discriminator.test.js
tools/
test/es6/
+31
View File
@@ -0,0 +1,31 @@
extends: 'eslint:recommended'
env:
node: true
mocha: true
rules:
comma-style: error
consistent-this:
- error
- _this
indent:
- error
- 2
- SwitchCase: 1
VariableDeclarator: 2
keyword-spacing: error
no-console: off
no-multi-spaces: error
no-spaced-func: error
no-trailing-spaces: error
quotes:
- error
- single
semi: error
space-before-blocks: error
space-before-function-paren:
- error
- never
space-infix-ops: error
space-unary-ops: error
+12
View File
@@ -0,0 +1,12 @@
<!-- *Before creating an issue please make sure you are using the latest version of mongoose -->
**Do you want to request a *feature* or report a *bug*?**
**What is the current behavior?**
**If the current behavior is a bug, please provide the steps to reproduce.**
<!-- If you can, provide a standalone script / gist to reproduce your issue -->
**What is the expected behavior?**
**Please mention your node.js, mongoose and MongoDB version.**
+9
View File
@@ -0,0 +1,9 @@
<!-- Thanks for submitting a pull request! Please provide enough information so that others can review your pull request. The two fields below are mandatory. -->
**Summary**
<!-- Explain the **motivation** for making this change. What existing problem does the pull request solve? -->
**Test plan**
<!-- Demonstrate the code is solid. Example: The exact commands you ran and their output, screenshots / videos if the pull request changes UI. -->
+25
View File
@@ -0,0 +1,25 @@
language: node_js
sudo: false
node_js:
- "9"
- "8"
- "7"
- "6"
- "5"
- "4"
- "0.12"
- "0.10"
- "iojs"
before_script:
- wget http://fastdl.mongodb.org/linux/mongodb-linux-x86_64-2.6.11.tgz
- tar -zxvf mongodb-linux-x86_64-2.6.11.tgz
- mkdir -p ./data/db/27017
- mkdir -p ./data/db/27000
- printf "\n--timeout 8000" >> ./test/mocha.opts
- ./mongodb-linux-x86_64-2.6.11/bin/mongod --fork --dbpath ./data/db/27017 --syslog --port 27017
- sleep 3
script:
- npm test
- npm run lint
notifications:
email: false
+62
View File
@@ -0,0 +1,62 @@
## Contributing to Mongoose
If you have a question about Mongoose (not a bug report) please post it to either [StackOverflow](http://stackoverflow.com/questions/tagged/mongoose), or on [Gitter](https://gitter.im/Automattic/mongoose?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
### Reporting bugs
- Before opening a new issue, look for existing [issues](https://github.com/Automattic/mongoose/issues) to avoid duplication. If the issue does not yet exist, [create one](https://github.com/Automattic/mongoose/issues/new).
- Please post any relevant code samples, preferably a standalone script that
reproduces your issue. Do **not** describe your issue in prose, show your
code.
- If the bug involves an error, please post the stack trace.
- Please post the version of mongoose and mongodb that you're using.
- Please write bug reports in JavaScript (ES5 or ES2015), not coffeescript, typescript, etc.
### Requesting new features
- Before opening a new issue, look for existing [issues](https://github.com/learnboost/mongoose/issues) to avoid duplication. If the issue does not yet exist, [create one](https://github.com/learnboost/mongoose/issues/new).
- Please describe a use case for it
- it would be ideal to include test cases as well
### Fixing bugs / Adding features
- Before starting to write code, look for existing [issues](https://github.com/learnboost/mongoose/issues). That way you avoid working on something that might not be of interest or that has been addressed already in a different branch. You can create a new issue [here](https://github.com/learnboost/mongoose/issues/new).
- _The source of this project is written in javascript, not coffeescript, therefore your bug reports should be written in javascript_.
- Fork the [repo](https://github.com/Automattic/mongoose) _or_ for small documentation changes, navigate to the source on github and click the [Edit](https://github.com/blog/844-forking-with-the-edit-button) button.
- Follow the general coding style of the rest of the project:
- 2 space tabs
- no trailing whitespace
- inline documentation for new methods, class members, etc.
- 1 space between conditionals, no space before function parenthesis
- `if (..) {`
- `for (..) {`
- `while (..) {`
- `function(err) {`
- Write tests and make sure they pass (tests are in the [test](https://github.com/Automattic/mongoose/tree/master/test) directory).
### Running the tests
- Open a terminal and navigate to the root of the project
- execute `npm install` to install the necessary dependencies
- start a mongodb instance on port 27017 if one isn't running already. `mongod --dbpath <path to store data> --port 27017`
- execute `npm test` to run the tests (we're using [mocha](http://mochajs.org/))
- or to execute a single test `npm test -- -g 'some regexp that matches the test description'`
- any mocha flags can be specified with `-- <mocha flags here>`
- For example, you can use `npm test -- -R spec` to use the spec reporter, rather than the dot reporter (by default, the test output looks like a bunch of dots)
### Documentation
To contribute to the [API documentation](http://mongoosejs.com/docs/api.html) just make your changes to the inline documentation of the appropriate [source code](https://github.com/Automattic/mongoose/tree/master/lib) in the master branch and submit a [pull request](https://help.github.com/articles/using-pull-requests/). You might also use the github [Edit](https://github.com/blog/844-forking-with-the-edit-button) button.
To contribute to the [guide](http://mongoosejs.com/docs/guide.html) or [quick start](http://mongoosejs.com/docs/index.html) docs, make your changes to the appropriate `.jade` files in the [docs](https://github.com/Automattic/mongoose/tree/master/docs) directory of the master branch and submit a pull request. Again, the [Edit](https://github.com/blog/844-forking-with-the-edit-button) button might work for you here.
If you'd like to preview your documentation changes, first commit your changes to your local master branch, then execute:
* `make docclean`
* `make gendocs`
* `node static.js`
Visit `http://localhost:8088` and you should see the docs with your local changes. Make sure you `git reset --hard` before commiting, because changes to `docs/*` should **not** be in PRs.
### Plugins website
The [plugins](http://plugins.mongoosejs.io/) site is also an [open source project](https://github.com/vkarpov15/mongooseplugins) that you can get involved with. Feel free to fork and improve it as well!
+4020
View File
File diff suppressed because it is too large Load Diff
+325
View File
@@ -0,0 +1,325 @@
# Mongoose
Mongoose is a [MongoDB](https://www.mongodb.org/) object modeling tool designed to work in an asynchronous environment.
[![Slack Status](http://slack.mongoosejs.io/badge.svg)](http://slack.mongoosejs.io)
[![Build Status](https://api.travis-ci.org/Automattic/mongoose.svg?branch=master)](https://travis-ci.org/Automattic/mongoose)
[![NPM version](https://badge.fury.io/js/mongoose.svg)](http://badge.fury.io/js/mongoose)
## Documentation
[mongoosejs.com](http://mongoosejs.com/)
## Support
- [Stack Overflow](http://stackoverflow.com/questions/tagged/mongoose)
- [Bug Reports](https://github.com/Automattic/mongoose/issues/)
- [Mongoose Slack Channel](http://slack.mongoosejs.io/)
- [Help Forum](http://groups.google.com/group/mongoose-orm)
- [MongoDB Support](https://docs.mongodb.org/manual/support/)
## Importing
```javascript
// Using Node.js `require()`
const mongoose = require('mongoose');
// Using ES6 imports
import mongoose from 'mongoose';
```
## Plugins
Check out the [plugins search site](http://plugins.mongoosejs.io/) to see hundreds of related modules from the community. Next, learn how to write your own plugin from the [docs](http://mongoosejs.com/docs/plugins.html) or [this blog post](http://thecodebarbarian.com/2015/03/06/guide-to-mongoose-plugins).
## Contributors
View all 300+ [contributors](https://github.com/Automattic/mongoose/graphs/contributors). Stand up and be counted as a [contributor](https://github.com/Automattic/mongoose/blob/master/CONTRIBUTING.md) too!
## Installation
First install [node.js](http://nodejs.org/) and [mongodb](https://www.mongodb.org/downloads). Then:
```sh
$ npm install mongoose
```
## Stability
The current stable branch is [master](https://github.com/Automattic/mongoose/tree/master). The [3.8.x](https://github.com/Automattic/mongoose/tree/3.8.x) branch contains legacy support for the 3.x release series, which is no longer under active development as of September 2015. The [3.8.x docs](http://mongoosejs.com/docs/3.8.x/) are still available.
## Overview
### Connecting to MongoDB
First, we need to define a connection. If your app uses only one database, you should use `mongoose.connect`. If you need to create additional connections, use `mongoose.createConnection`.
Both `connect` and `createConnection` take a `mongodb://` URI, or the parameters `host, database, port, options`.
```js
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/my_database');
```
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`.
**Note:** _If the local connection fails then try using 127.0.0.1 instead of localhost. Sometimes issues may arise when the local hostname has been changed._
**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.
### Defining a Model
Models are defined through the `Schema` interface.
```js
var Schema = mongoose.Schema,
ObjectId = Schema.ObjectId;
var BlogPost = new Schema({
author : ObjectId,
title : String,
body : String,
date : Date
});
```
Aside from defining the structure of your documents and the types of data you're storing, a Schema handles the definition of:
* [Validators](http://mongoosejs.com/docs/validation.html) (async and sync)
* [Defaults](http://mongoosejs.com/docs/api.html#schematype_SchemaType-default)
* [Getters](http://mongoosejs.com/docs/api.html#schematype_SchemaType-get)
* [Setters](http://mongoosejs.com/docs/api.html#schematype_SchemaType-set)
* [Indexes](http://mongoosejs.com/docs/guide.html#indexes)
* [Middleware](http://mongoosejs.com/docs/middleware.html)
* [Methods](http://mongoosejs.com/docs/guide.html#methods) definition
* [Statics](http://mongoosejs.com/docs/guide.html#statics) definition
* [Plugins](http://mongoosejs.com/docs/plugins.html)
* [pseudo-JOINs](http://mongoosejs.com/docs/populate.html)
The following example shows some of these features:
```js
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 },
buff: Buffer
});
// a setter
Comment.path('name').set(function (v) {
return capitalize(v);
});
// middleware
Comment.pre('save', function (next) {
notify(this.get('email'));
next();
});
```
Take a look at the example in `examples/schema.js` for an end-to-end example of a typical setup.
### Accessing a Model
Once we define a model through `mongoose.model('ModelName', mySchema)`, we can access it through the same function
```js
var myModel = mongoose.model('ModelName');
```
Or just do it all at once
```js
var MyModel = mongoose.model('ModelName', mySchema);
```
The first argument is the _singular_ name of the collection your model is for. **Mongoose automatically looks for the _plural_ version of your model name.** For example, if you use
```js
var MyModel = mongoose.model('Ticket', mySchema);
```
Then Mongoose will create the model for your __tickets__ collection, not your __ticket__ collection.
Once we have our model, we can then instantiate it, and save it:
```js
var instance = new MyModel();
instance.my.key = 'hello';
instance.save(function (err) {
//
});
```
Or we can find documents from the same collection
```js
MyModel.find({}, function (err, docs) {
// docs.forEach
});
```
You can also `findOne`, `findById`, `update`, etc. For more details check out [the docs](http://mongoosejs.com/docs/queries.html).
**Important!** If you opened a separate connection using `mongoose.createConnection()` but attempt to access the model through `mongoose.model('ModelName')` it will not work as expected since it is not hooked up to an active db connection. In this case access your model through the connection you created:
```js
var conn = mongoose.createConnection('your connection string'),
MyModel = conn.model('ModelName', schema),
m = new MyModel;
m.save(); // works
```
vs
```js
var conn = mongoose.createConnection('your connection string'),
MyModel = mongoose.model('ModelName', schema),
m = new MyModel;
m.save(); // does not work b/c the default connection object was never connected
```
### Embedded Documents
In the first example snippet, we defined a key in the Schema that looks like:
```
comments: [Comment]
```
Where `Comment` is a `Schema` we created. This means that creating embedded documents is as simple as:
```js
// retrieve my model
var BlogPost = mongoose.model('BlogPost');
// create a blog post
var post = new BlogPost();
// create a comment
post.comments.push({ title: 'My comment' });
post.save(function (err) {
if (!err) console.log('Success!');
});
```
The same goes for removing them:
```js
BlogPost.findById(myId, function (err, post) {
if (!err) {
post.comments[0].remove();
post.save(function (err) {
// do something
});
}
});
```
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!
### Middleware
See the [docs](http://mongoosejs.com/docs/middleware.html) page.
#### Intercepting and mutating method arguments
You can intercept method arguments via middleware.
For example, this would allow you to broadcast changes about your Documents every time someone `set`s a path in your Document to a new value:
```js
schema.pre('set', function (next, path, val, typel) {
// `this` is the current Document
this.emit('set', path, val);
// Pass control to the next pre
next();
});
```
Moreover, you can mutate the incoming `method` arguments so that subsequent middleware see different values for those arguments. To do so, just pass the new values to `next`:
```js
.pre(method, function firstPre (next, methodArg1, methodArg2) {
// Mutate methodArg1
next("altered-" + methodArg1.toString(), methodArg2);
});
// pre declaration is chainable
.pre(method, function secondPre (next, methodArg1, methodArg2) {
console.log(methodArg1);
// => 'altered-originalValOfMethodArg1'
console.log(methodArg2);
// => 'originalValOfMethodArg2'
// Passing no arguments to `next` automatically passes along the current argument values
// i.e., the following `next()` is equivalent to `next(methodArg1, methodArg2)`
// and also equivalent to, with the example method arg
// values, `next('altered-originalValOfMethodArg1', 'originalValOfMethodArg2')`
next();
});
```
#### Schema gotcha
`type`, when used in a schema has special meaning within Mongoose. If your schema requires using `type` as a nested property you must use object notation:
```js
new Schema({
broken: { type: Boolean },
asset: {
name: String,
type: String // uh oh, it broke. asset will be interpreted as String
}
});
new Schema({
works: { type: Boolean },
asset: {
name: String,
type: { type: String } // works. asset is an object with a type property
}
});
```
### Driver Access
Mongoose is built on top of the [official MongoDB Node.js driver](https://github.com/mongodb/node-mongodb-native). Each mongoose model keeps a reference to a [native MongoDB driver collection](http://mongodb.github.io/node-mongodb-native/2.1/api/Collection.html). The collection object can be accessed using `YourModel.collection`. However, using the collection object directly bypasses all mongoose features, including hooks, validation, etc. The one
notable exception that `YourModel.collection` still buffers
commands. As such, `YourModel.collection.find()` will **not**
return a cursor.
## API Docs
Find the API docs [here](http://mongoosejs.com/docs/api.html), generated using [dox](https://github.com/tj/dox)
and [acquit](https://github.com/vkarpov15/acquit).
## License
Copyright (c) 2010 LearnBoost &lt;dev@learnboost.com&gt;
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+41
View File
@@ -0,0 +1,41 @@
This directory contains runnable sample mongoose programs.
To run:
- first install [Node.js](http://nodejs.org/)
- from the root of the project, execute `npm install -d`
- in the example directory, run `npm install -d`
- from the command line, execute: `node example.js`, replacing "example.js" with the name of a program.
Goal is to show:
- ~~global schemas~~
- ~~GeoJSON schemas / use (with crs)~~
- text search (once MongoDB removes the "Experimental/beta" label)
- ~~lean queries~~
- ~~statics~~
- methods and statics on subdocs
- custom types
- ~~querybuilder~~
- ~~promises~~
- accessing driver collection, db
- ~~connecting to replica sets~~
- connecting to sharded clusters
- enabling a fail fast mode
- on the fly schemas
- storing files
- ~~map reduce~~
- ~~aggregation~~
- advanced hooks
- using $elemMatch to return a subset of an array
- query casting
- upserts
- pagination
- express + mongoose session handling
- ~~group by (use aggregation)~~
- authentication
- schema migration techniques
- converting documents to plain objects (show transforms)
- how to $unset
+103
View File
@@ -0,0 +1,103 @@
// import async to make control flow simplier
var async = require('async');
// import the rest of the normal stuff
var mongoose = require('../../lib');
require('./person.js')();
var Person = mongoose.model('Person');
// define some dummy data
var data = [
{
name: 'bill',
age: 25,
birthday: new Date().setFullYear((new Date().getFullYear() - 25)),
gender: 'Male',
likes: ['movies', 'games', 'dogs']
},
{
name: 'mary',
age: 30,
birthday: new Date().setFullYear((new Date().getFullYear() - 30)),
gender: 'Female',
likes: ['movies', 'birds', 'cats']
},
{
name: 'bob',
age: 21,
birthday: new Date().setFullYear((new Date().getFullYear() - 21)),
gender: 'Male',
likes: ['tv', 'games', 'rabbits']
},
{
name: 'lilly',
age: 26,
birthday: new Date().setFullYear((new Date().getFullYear() - 26)),
gender: 'Female',
likes: ['books', 'cats', 'dogs']
},
{
name: 'alucard',
age: 1000,
birthday: new Date().setFullYear((new Date().getFullYear() - 1000)),
gender: 'Male',
likes: ['glasses', 'wine', 'the night']
}
];
mongoose.connect('mongodb://localhost/persons', function(err) {
if (err) throw err;
// create all of the dummy people
async.each(data, function(item, cb) {
Person.create(item, cb);
}, function(err) {
if (err) {
// handle error
}
// run an aggregate query that will get all of the people who like a given
// item. To see the full documentation on ways to use the aggregate
// framework, see http://docs.mongodb.org/manual/core/aggregation/
Person.aggregate(
// select the fields we want to deal with
{$project: {name: 1, likes: 1}},
// unwind 'likes', which will create a document for each like
{$unwind: '$likes'},
// group everything by the like and then add each name with that like to
// the set for the like
{$group: {
_id: {likes: '$likes'},
likers: {$addToSet: '$name'}
}},
function(err, result) {
if (err) throw err;
console.log(result);
/* [
{ _id: { likes: 'the night' }, likers: [ 'alucard' ] },
{ _id: { likes: 'wine' }, likers: [ 'alucard' ] },
{ _id: { likes: 'books' }, likers: [ 'lilly' ] },
{ _id: { likes: 'glasses' }, likers: [ 'alucard' ] },
{ _id: { likes: 'birds' }, likers: [ 'mary' ] },
{ _id: { likes: 'rabbits' }, likers: [ 'bob' ] },
{ _id: { likes: 'cats' }, likers: [ 'lilly', 'mary' ] },
{ _id: { likes: 'dogs' }, likers: [ 'lilly', 'bill' ] },
{ _id: { likes: 'tv' }, likers: [ 'bob' ] },
{ _id: { likes: 'games' }, likers: [ 'bob', 'bill' ] },
{ _id: { likes: 'movies' }, likers: [ 'mary', 'bill' ] }
] */
cleanup();
});
});
});
function cleanup() {
Person.remove(function() {
mongoose.disconnect();
});
}
+14
View File
@@ -0,0 +1,14 @@
{
"name": "aggregate-example",
"private": "true",
"version": "0.0.0",
"description": "deps for aggregate example",
"main": "aggregate.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"dependencies": { "async": "*" },
"repository": "",
"author": "",
"license": "BSD"
}
+17
View File
@@ -0,0 +1,17 @@
// import the necessary modules
var mongoose = require('../../lib');
var Schema = mongoose.Schema;
// create an export function to encapsulate the model creation
module.exports = function() {
// define schema
var PersonSchema = new Schema({
name: String,
age: Number,
birthday: Date,
gender: String,
likes: [String]
});
mongoose.model('Person', PersonSchema);
};
+77
View File
@@ -0,0 +1,77 @@
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
console.log('Running mongoose version %s', mongoose.version);
/**
* Schema
*/
var CharacterSchema = Schema({
name: {
type: String,
required: true
},
health: {
type: Number,
min: 0,
max: 100
}
});
/**
* Methods
*/
CharacterSchema.methods.attack = function() {
console.log('%s is attacking', this.name);
};
/**
* Character model
*/
var Character = mongoose.model('Character', CharacterSchema);
/**
* Connect to the database on localhost with
* the default port (27017)
*/
var dbname = 'mongoose-example-doc-methods-' + ((Math.random() * 10000) | 0);
var uri = 'mongodb://localhost/' + dbname;
console.log('connecting to %s', uri);
mongoose.connect(uri, function(err) {
// if we failed to connect, abort
if (err) throw err;
// we connected ok
example();
});
/**
* Use case
*/
function example() {
Character.create({name: 'Link', health: 100}, function(err, link) {
if (err) return done(err);
console.log('found', link);
link.attack(); // 'Link is attacking'
done();
});
}
/**
* Clean up
*/
function done(err) {
if (err) console.error(err);
mongoose.connection.db.dropDatabase(function() {
mongoose.disconnect();
});
}
+1
View File
@@ -0,0 +1 @@
Mongoose + Express examples
@@ -0,0 +1,6 @@
To run:
- Execute `npm install` from this directory
- Execute `node app.js`
- Navigate to `localhost:8000`
@@ -0,0 +1,17 @@
var express = require('express');
var mongoose = require('../../../lib');
var uri = 'mongodb://localhost/mongoose-shared-connection';
global.db = mongoose.createConnection(uri);
var routes = require('./routes');
var app = express();
app.get('/', routes.home);
app.get('/insert', routes.insert);
app.get('/name', routes.modelName);
app.listen(8000, function() {
console.log('listening on http://localhost:8000');
});
@@ -0,0 +1,5 @@
var Schema = require('../../../lib').Schema;
var mySchema = Schema({name: String});
/* global db */
module.exports = db.model('MyModel', mySchema);
@@ -0,0 +1,14 @@
{
"name": "connection-sharing",
"private": "true",
"version": "0.0.0",
"description": "ERROR: No README.md file found!",
"main": "app.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"dependencies": { "express": "3.1.1" },
"repository": "",
"author": "",
"license": "BSD"
}
@@ -0,0 +1,20 @@
var model = require('./modelA');
exports.home = function(req, res, next) {
model.find(function(err, docs) {
if (err) return next(err);
res.send(docs);
});
};
exports.modelName = function(req, res) {
res.send('my model name is ' + model.modelName);
};
exports.insert = function(req, res, next) {
model.create({name: 'inserting ' + Date.now()}, function(err, doc) {
if (err) return next(err);
res.send(doc);
});
};
@@ -0,0 +1,22 @@
// import the necessary modules
var mongoose = require('../../lib');
var Schema = mongoose.Schema;
// create an export function to encapsulate the model creation
module.exports = function() {
// define schema
// NOTE : This object must conform *precisely* to the geoJSON specification
// you cannot embed a geoJSON doc inside a model or anything like that- IT
// MUST BE VANILLA
var LocationObject = new Schema({
loc: {
type: {type: String},
coordinates: []
}
});
// define the index
LocationObject.index({loc: '2dsphere'});
mongoose.model('Location', LocationObject);
};
@@ -0,0 +1,56 @@
// import async to make control flow simplier
var async = require('async');
// import the rest of the normal stuff
var mongoose = require('../../lib');
require('./geoJSONSchema.js')();
var Location = mongoose.model('Location');
// define some dummy data
// note: the type can be Point, LineString, or Polygon
var data = [
{loc: {type: 'Point', coordinates: [-20.0, 5.0]}},
{loc: {type: 'Point', coordinates: [6.0, 10.0]}},
{loc: {type: 'Point', coordinates: [34.0, -50.0]}},
{loc: {type: 'Point', coordinates: [-100.0, 70.0]}},
{loc: {type: 'Point', coordinates: [38.0, 38.0]}}
];
mongoose.connect('mongodb://localhost/locations', function(err) {
if (err) {
throw err;
}
Location.on('index', function(err) {
if (err) {
throw err;
}
// create all of the dummy locations
async.each(data, function(item, cb) {
Location.create(item, cb);
}, function(err) {
if (err) {
throw err;
}
// create the location we want to search for
var coords = {type: 'Point', coordinates: [-5, 5]};
// search for it
Location.find({loc: {$near: coords}}).limit(1).exec(function(err, res) {
if (err) {
throw err;
}
console.log('Closest to %s is %s', JSON.stringify(coords), res);
cleanup();
});
});
});
});
function cleanup() {
Location.remove(function() {
mongoose.disconnect();
});
}
+100
View File
@@ -0,0 +1,100 @@
// import async to make control flow simplier
var async = require('async');
// import the rest of the normal stuff
var mongoose = require('../../lib');
require('./person.js')();
var Person = mongoose.model('Person');
// define some dummy data
var data = [
{
name: 'bill',
age: 25,
birthday: new Date().setFullYear((new Date().getFullYear() - 25)),
gender: 'Male',
likes: ['movies', 'games', 'dogs'],
loc: [0, 0]
},
{
name: 'mary',
age: 30,
birthday: new Date().setFullYear((new Date().getFullYear() - 30)),
gender: 'Female',
likes: ['movies', 'birds', 'cats'],
loc: [1, 1]
},
{
name: 'bob',
age: 21,
birthday: new Date().setFullYear((new Date().getFullYear() - 21)),
gender: 'Male',
likes: ['tv', 'games', 'rabbits'],
loc: [3, 3]
},
{
name: 'lilly',
age: 26,
birthday: new Date().setFullYear((new Date().getFullYear() - 26)),
gender: 'Female',
likes: ['books', 'cats', 'dogs'],
loc: [6, 6]
},
{
name: 'alucard',
age: 1000,
birthday: new Date().setFullYear((new Date().getFullYear() - 1000)),
gender: 'Male',
likes: ['glasses', 'wine', 'the night'],
loc: [10, 10]
}
];
mongoose.connect('mongodb://localhost/persons', function(err) {
if (err) {
throw err;
}
// create all of the dummy people
async.each(data, function(item, cb) {
Person.create(item, cb);
}, function(err) {
if (err) {
// handler error
}
// let's find the closest person to bob
Person.find({name: 'bob'}, function(err, res) {
if (err) {
throw err;
}
res[0].findClosest(function(err, closest) {
if (err) {
throw err;
}
console.log('%s is closest to %s', res[0].name, closest);
// we can also just query straight off of the model. For more
// information about geospatial queries and indexes, see
// http://docs.mongodb.org/manual/applications/geospatial-indexes/
var coords = [7, 7];
Person.find({loc: {$nearSphere: coords}}).limit(1).exec(function(err, res) {
console.log('Closest to %s is %s', coords, res);
cleanup();
});
});
});
});
});
function cleanup() {
Person.remove(function() {
mongoose.disconnect();
});
}
+14
View File
@@ -0,0 +1,14 @@
{
"name": "geospatial-example",
"private": "true",
"version": "0.0.0",
"description": "deps for geospatial example",
"main": "geospatial.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"dependencies": { "async": "*" },
"repository": "",
"author": "",
"license": "BSD"
}
+27
View File
@@ -0,0 +1,27 @@
// import the necessary modules
var mongoose = require('../../lib');
var Schema = mongoose.Schema;
// create an export function to encapsulate the model creation
module.exports = function() {
// define schema
var PersonSchema = new Schema({
name: String,
age: Number,
birthday: Date,
gender: String,
likes: [String],
// define the geospatial field
loc: {type: [Number], index: '2d'}
});
// define a method to find the closest person
PersonSchema.methods.findClosest = function(cb) {
return this.model('Person').find({
loc: {$nearSphere: this.loc},
name: {$ne: this.name}
}).limit(1).exec(cb);
};
mongoose.model('Person', PersonSchema);
};
@@ -0,0 +1,47 @@
var mongoose = require('../../lib');
// import the global schema, this can be done in any file that needs the model
require('./person.js')();
// grab the person model object
var Person = mongoose.model('Person');
// connect to a server to do a quick write / read example
mongoose.connect('mongodb://localhost/persons', function(err) {
if (err) {
throw err;
}
Person.create({
name: 'bill',
age: 25,
birthday: new Date().setFullYear((new Date().getFullYear() - 25))
}, function(err, bill) {
if (err) {
throw err;
}
console.log('People added to db: %s', bill.toString());
Person.find({}, function(err, people) {
if (err) {
throw err;
}
people.forEach(function(person) {
console.log('People in the db: %s', person.toString());
});
// make sure to clean things up after we're done
setTimeout(function() {
cleanup();
}, 2000);
});
});
});
function cleanup() {
Person.remove(function() {
mongoose.disconnect();
});
}
+14
View File
@@ -0,0 +1,14 @@
// import the necessary modules
var mongoose = require('../../lib');
var Schema = mongoose.Schema;
// create an export function to encapsulate the model creation
module.exports = function() {
// define schema
var PersonSchema = new Schema({
name: String,
age: Number,
birthday: Date
});
mongoose.model('Person', PersonSchema);
};
+84
View File
@@ -0,0 +1,84 @@
// import async to make control flow simplier
var async = require('async');
// import the rest of the normal stuff
var mongoose = require('../../lib');
require('./person.js')();
var Person = mongoose.model('Person');
// define some dummy data
var data = [
{
name: 'bill',
age: 25,
birthday: new Date().setFullYear((new Date().getFullYear() - 25)),
gender: 'Male',
likes: ['movies', 'games', 'dogs']
},
{
name: 'mary',
age: 30,
birthday: new Date().setFullYear((new Date().getFullYear() - 30)),
gender: 'Female',
likes: ['movies', 'birds', 'cats']
},
{
name: 'bob',
age: 21,
birthday: new Date().setFullYear((new Date().getFullYear() - 21)),
gender: 'Male',
likes: ['tv', 'games', 'rabbits']
},
{
name: 'lilly',
age: 26,
birthday: new Date().setFullYear((new Date().getFullYear() - 26)),
gender: 'Female',
likes: ['books', 'cats', 'dogs']
},
{
name: 'alucard',
age: 1000,
birthday: new Date().setFullYear((new Date().getFullYear() - 1000)),
gender: 'Male',
likes: ['glasses', 'wine', 'the night']
}
];
mongoose.connect('mongodb://localhost/persons', function(err) {
if (err) throw err;
// create all of the dummy people
async.each(data, function(item, cb) {
Person.create(item, cb);
}, function(err) {
if (err) {
// handle error
}
// lean queries return just plain javascript objects, not
// MongooseDocuments. This makes them good for high performance read
// situations
// when using .lean() the default is true, but you can explicitly set the
// value by passing in a boolean value. IE. .lean(false)
var q = Person.find({age: {$lt: 1000}}).sort('age').limit(2).lean();
q.exec(function(err, results) {
if (err) throw err;
console.log('Are the results MongooseDocuments?: %s', results[0] instanceof mongoose.Document);
console.log(results);
cleanup();
});
});
});
function cleanup() {
Person.remove(function() {
mongoose.disconnect();
});
}
+14
View File
@@ -0,0 +1,14 @@
{
"name": "lean-example",
"private": "true",
"version": "0.0.0",
"description": "deps for lean example",
"main": "lean.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"dependencies": { "async": "*" },
"repository": "",
"author": "",
"license": "BSD"
}
+16
View File
@@ -0,0 +1,16 @@
// import the necessary modules
var mongoose = require('../../lib');
var Schema = mongoose.Schema;
// create an export function to encapsulate the model creation
module.exports = function() {
// define schema
var PersonSchema = new Schema({
name: String,
age: Number,
birthday: Date,
gender: String,
likes: [String]
});
mongoose.model('Person', PersonSchema);
};
+100
View File
@@ -0,0 +1,100 @@
// import async to make control flow simplier
var async = require('async');
// import the rest of the normal stuff
var mongoose = require('../../lib');
require('./person.js')();
var Person = mongoose.model('Person');
// define some dummy data
var data = [
{
name: 'bill',
age: 25,
birthday: new Date().setFullYear((new Date().getFullYear() - 25)),
gender: 'Male'
},
{
name: 'mary',
age: 30,
birthday: new Date().setFullYear((new Date().getFullYear() - 30)),
gender: 'Female'
},
{
name: 'bob',
age: 21,
birthday: new Date().setFullYear((new Date().getFullYear() - 21)),
gender: 'Male'
},
{
name: 'lilly',
age: 26,
birthday: new Date().setFullYear((new Date().getFullYear() - 26)),
gender: 'Female'
},
{
name: 'alucard',
age: 1000,
birthday: new Date().setFullYear((new Date().getFullYear() - 1000)),
gender: 'Male'
}
];
mongoose.connect('mongodb://localhost/persons', function(err) {
if (err) throw err;
// create all of the dummy people
async.each(data, function(item, cb) {
Person.create(item, cb);
}, function(err) {
if (err) {
// handle error
}
// alright, simple map reduce example. We will find the total ages of each
// gender
// create the options object
var o = {};
o.map = function() {
// in this function, 'this' refers to the current document being
// processed. Return the (gender, age) tuple using
/* global emit */
emit(this.gender, this.age);
};
// the reduce function receives the array of ages that are grouped by the
// id, which in this case is the gender
o.reduce = function(id, ages) {
return Array.sum(ages);
};
// other options that can be specified
// o.query = { age : { $lt : 1000 }}; // the query object
// o.limit = 3; // max number of documents
// o.keeptemp = true; // default is false, specifies whether to keep temp data
// o.finalize = someFunc; // function called after reduce
// o.scope = {}; // the scope variable exposed to map/reduce/finalize
// o.jsMode = true; // default is false, force execution to stay in JS
o.verbose = true; // default is false, provide stats on the job
// o.out = {}; // objects to specify where output goes, by default is
// returned, but can also be stored in a new collection
// see: http://mongoosejs.com/docs/api.html#model_Model.mapReduce
Person.mapReduce(o, function(err, results, stats) {
console.log('map reduce took %d ms', stats.processtime);
console.log(results);
cleanup();
});
});
});
function cleanup() {
Person.remove(function() {
mongoose.disconnect();
});
}
+14
View File
@@ -0,0 +1,14 @@
{
"name": "map-reduce-example",
"private": "true",
"version": "0.0.0",
"description": "deps for map reduce example",
"main": "mapreduce.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"dependencies": { "async": "*" },
"repository": "",
"author": "",
"license": "BSD"
}
+16
View File
@@ -0,0 +1,16 @@
// import the necessary modules
var mongoose = require('../../lib');
var Schema = mongoose.Schema;
// create an export function to encapsulate the model creation
module.exports = function() {
// define schema
var PersonSchema = new Schema({
name: String,
age: Number,
birthday: Date,
gender: String
});
mongoose.model('Person', PersonSchema);
};
@@ -0,0 +1,134 @@
var assert = require('assert');
var mongoose = require('../../lib');
var Schema = mongoose.Schema;
var ObjectId = mongoose.Types.ObjectId;
/**
* Connect to the db
*/
var dbname = 'testing_populateAdInfinitum_' + require('../../lib/utils').random();
mongoose.connect('localhost', dbname);
mongoose.connection.on('error', function() {
console.error('connection error', arguments);
});
/**
* Schemas
*/
var user = new Schema({
name: String,
friends: [{
type: Schema.ObjectId,
ref: 'User'
}]
});
var User = mongoose.model('User', user);
var blogpost = Schema({
title: String,
tags: [String],
author: {
type: Schema.ObjectId,
ref: 'User'
}
});
var BlogPost = mongoose.model('BlogPost', blogpost);
/**
* example
*/
mongoose.connection.on('open', function() {
/**
* Generate data
*/
var userIds = [new ObjectId, new ObjectId, new ObjectId, new ObjectId];
var users = [];
users.push({
_id: userIds[0],
name: 'mary',
friends: [userIds[1], userIds[2], userIds[3]]
});
users.push({
_id: userIds[1],
name: 'bob',
friends: [userIds[0], userIds[2], userIds[3]]
});
users.push({
_id: userIds[2],
name: 'joe',
friends: [userIds[0], userIds[1], userIds[3]]
});
users.push({
_id: userIds[3],
name: 'sally',
friends: [userIds[0], userIds[1], userIds[2]]
});
User.create(users, function(err) {
assert.ifError(err);
var blogposts = [];
blogposts.push({
title: 'blog 1',
tags: ['fun', 'cool'],
author: userIds[3]
});
blogposts.push({
title: 'blog 2',
tags: ['cool'],
author: userIds[1]
});
blogposts.push({
title: 'blog 3',
tags: ['fun', 'odd'],
author: userIds[2]
});
BlogPost.create(blogposts, function(err) {
assert.ifError(err);
/**
* Population
*/
BlogPost
.find({tags: 'fun'})
.lean()
.populate('author')
.exec(function(err, docs) {
assert.ifError(err);
/**
* Populate the populated documents
*/
var opts = {
path: 'author.friends',
select: 'name',
options: {limit: 2}
};
BlogPost.populate(docs, opts, function(err, docs) {
assert.ifError(err);
console.log('populated');
var s = require('util').inspect(docs, {depth: null, colors: true});
console.log(s);
done();
});
});
});
});
});
function done(err) {
if (err) console.error(err.stack);
mongoose.connection.db.dropDatabase(function() {
mongoose.connection.close();
});
}
@@ -0,0 +1,103 @@
var mongoose = require('../../lib');
var Schema = mongoose.Schema;
console.log('Running mongoose version %s', mongoose.version);
/**
* Console schema
*/
var consoleSchema = Schema({
name: String,
manufacturer: String,
released: Date
});
var Console = mongoose.model('Console', consoleSchema);
/**
* Game schema
*/
var gameSchema = Schema({
name: String,
developer: String,
released: Date,
consoles: [{
type: Schema.Types.ObjectId,
ref: 'Console'
}]
});
var Game = mongoose.model('Game', gameSchema);
/**
* Connect to the console database on localhost with
* the default port (27017)
*/
mongoose.connect('mongodb://localhost/console', function(err) {
// if we failed to connect, abort
if (err) throw err;
// we connected ok
createData();
});
/**
* Data generation
*/
function createData() {
Console.create(
{
name: 'Nintendo 64',
manufacturer: 'Nintendo',
released: 'September 29, 1996'
},
function(err, nintendo64) {
if (err) return done(err);
Game.create({
name: 'Legend of Zelda: Ocarina of Time',
developer: 'Nintendo',
released: new Date('November 21, 1998'),
consoles: [nintendo64]
},
function(err) {
if (err) return done(err);
example();
});
}
);
}
/**
* Population
*/
function example() {
Game
.findOne({name: /^Legend of Zelda/})
.populate('consoles')
.exec(function(err, ocinara) {
if (err) return done(err);
console.log(
'"%s" was released for the %s on %s',
ocinara.name,
ocinara.consoles[0].name,
ocinara.released.toLocaleDateString()
);
done();
});
}
function done(err) {
if (err) console.error(err);
Console.remove(function() {
Game.remove(function() {
mongoose.disconnect();
});
});
}
@@ -0,0 +1,109 @@
var mongoose = require('../../lib');
var Schema = mongoose.Schema;
console.log('Running mongoose version %s', mongoose.version);
/**
* Console schema
*/
var consoleSchema = Schema({
name: String,
manufacturer: String,
released: Date
});
var Console = mongoose.model('Console', consoleSchema);
/**
* Game schema
*/
var gameSchema = Schema({
name: String,
developer: String,
released: Date,
consoles: [{
type: Schema.Types.ObjectId,
ref: 'Console'
}]
});
var Game = mongoose.model('Game', gameSchema);
/**
* Connect to the console database on localhost with
* the default port (27017)
*/
mongoose.connect('mongodb://localhost/console', function(err) {
// if we failed to connect, abort
if (err) throw err;
// we connected ok
createData();
});
/**
* Data generation
*/
function createData() {
Console.create(
{
name: 'Nintendo 64',
manufacturer: 'Nintendo',
released: 'September 29, 1996'
},
function(err, nintendo64) {
if (err) return done(err);
Game.create({
name: 'Legend of Zelda: Ocarina of Time',
developer: 'Nintendo',
released: new Date('November 21, 1998'),
consoles: [nintendo64]
},
function(err) {
if (err) return done(err);
example();
});
}
);
}
/**
* Population
*/
function example() {
Game
.findOne({name: /^Legend of Zelda/})
.exec(function(err, ocinara) {
if (err) return done(err);
console.log('"%s" console _id: %s', ocinara.name, ocinara.consoles[0]);
// population of existing document
ocinara.populate('consoles', function(err) {
if (err) return done(err);
console.log(
'"%s" was released for the %s on %s',
ocinara.name,
ocinara.consoles[0].name,
ocinara.released.toLocaleDateString()
);
done();
});
});
}
function done(err) {
if (err) console.error(err);
Console.remove(function() {
Game.remove(function() {
mongoose.disconnect();
});
});
}
@@ -0,0 +1,124 @@
var mongoose = require('../../lib');
var Schema = mongoose.Schema;
console.log('Running mongoose version %s', mongoose.version);
/**
* Console schema
*/
var consoleSchema = Schema({
name: String,
manufacturer: String,
released: Date
});
var Console = mongoose.model('Console', consoleSchema);
/**
* Game schema
*/
var gameSchema = Schema({
name: String,
developer: String,
released: Date,
consoles: [{
type: Schema.Types.ObjectId,
ref: 'Console'
}]
});
var Game = mongoose.model('Game', gameSchema);
/**
* Connect to the console database on localhost with
* the default port (27017)
*/
mongoose.connect('mongodb://localhost/console', function(err) {
// if we failed to connect, abort
if (err) throw err;
// we connected ok
createData();
});
/**
* Data generation
*/
function createData() {
Console.create(
{
name: 'Nintendo 64',
manufacturer: 'Nintendo',
released: 'September 29, 1996'
},
{
name: 'Super Nintendo',
manufacturer: 'Nintendo',
released: 'August 23, 1991'
},
function(err, nintendo64, superNintendo) {
if (err) return done(err);
Game.create(
{
name: 'Legend of Zelda: Ocarina of Time',
developer: 'Nintendo',
released: new Date('November 21, 1998'),
consoles: [nintendo64]
},
{
name: 'Mario Kart',
developer: 'Nintendo',
released: 'September 1, 1992',
consoles: [superNintendo]
},
function(err) {
if (err) return done(err);
example();
}
);
}
);
}
/**
* Population
*/
function example() {
Game
.find({})
.exec(function(err, games) {
if (err) return done(err);
console.log('found %d games', games.length);
var options = {path: 'consoles', select: 'name released -_id'};
Game.populate(games, options, function(err, games) {
if (err) return done(err);
games.forEach(function(game) {
console.log(
'"%s" was released for the %s on %s',
game.name,
game.consoles[0].name,
game.released.toLocaleDateString()
);
});
done();
});
});
}
function done(err) {
if (err) console.error(err);
Console.remove(function() {
Game.remove(function() {
mongoose.disconnect();
});
});
}
@@ -0,0 +1,138 @@
var mongoose = require('../../lib');
var Schema = mongoose.Schema;
console.log('Running mongoose version %s', mongoose.version);
/**
* Console schema
*/
var consoleSchema = Schema({
name: String,
manufacturer: String,
released: Date
});
var Console = mongoose.model('Console', consoleSchema);
/**
* Game schema
*/
var gameSchema = Schema({
name: String,
developer: String,
released: Date,
consoles: [{
type: Schema.Types.ObjectId,
ref: 'Console'
}]
});
var Game = mongoose.model('Game', gameSchema);
/**
* Connect to the console database on localhost with
* the default port (27017)
*/
mongoose.connect('mongodb://localhost/console', function(err) {
// if we failed to connect, abort
if (err) throw err;
// we connected ok
createData();
});
/**
* Data generation
*/
function createData() {
Console.create(
{
name: 'Nintendo 64',
manufacturer: 'Nintendo',
released: 'September 29, 1996'
},
{
name: 'Super Nintendo',
manufacturer: 'Nintendo',
released: 'August 23, 1991'
},
{
name: 'XBOX 360',
manufacturer: 'Microsoft',
released: 'November 22, 2005'
},
function(err, nintendo64, superNintendo, xbox360) {
if (err) return done(err);
Game.create(
{
name: 'Legend of Zelda: Ocarina of Time',
developer: 'Nintendo',
released: new Date('November 21, 1998'),
consoles: [nintendo64]
},
{
name: 'Mario Kart',
developer: 'Nintendo',
released: 'September 1, 1992',
consoles: [superNintendo]
},
{
name: 'Perfect Dark Zero',
developer: 'Rare',
released: 'November 17, 2005',
consoles: [xbox360]
},
function(err) {
if (err) return done(err);
example();
}
);
}
);
}
/**
* Population
*/
function example() {
Game
.find({})
.populate({
path: 'consoles',
match: {manufacturer: 'Nintendo'},
select: 'name',
options: {comment: 'population'}
})
.exec(function(err, games) {
if (err) return done(err);
games.forEach(function(game) {
console.log(
'"%s" was released for the %s on %s',
game.name,
game.consoles.length ? game.consoles[0].name : '??',
game.released.toLocaleDateString()
);
});
return done();
});
}
/**
* Clean up
*/
function done(err) {
if (err) console.error(err);
Console.remove(function() {
Game.remove(function() {
mongoose.disconnect();
});
});
}
@@ -0,0 +1,106 @@
var mongoose = require('../../lib');
var Schema = mongoose.Schema;
console.log('Running mongoose version %s', mongoose.version);
/**
* Console schema
*/
var consoleSchema = Schema({
name: String,
manufacturer: String,
released: Date
});
var Console = mongoose.model('Console', consoleSchema);
/**
* Game schema
*/
var gameSchema = Schema({
name: String,
developer: String,
released: Date,
consoles: [{
type: Schema.Types.ObjectId,
ref: 'Console'
}]
});
var Game = mongoose.model('Game', gameSchema);
/**
* Connect to the console database on localhost with
* the default port (27017)
*/
mongoose.connect('mongodb://localhost/console', function(err) {
// if we failed to connect, abort
if (err) throw err;
// we connected ok
createData();
});
/**
* Data generation
*/
function createData() {
Console.create(
{
name: 'Nintendo 64',
manufacturer: 'Nintendo',
released: 'September 29, 1996'
},
function(err, nintendo64) {
if (err) return done(err);
Game.create(
{
name: 'Legend of Zelda: Ocarina of Time',
developer: 'Nintendo',
released: new Date('November 21, 1998'),
consoles: [nintendo64]
},
function(err) {
if (err) return done(err);
example();
}
);
}
);
}
/**
* Population
*/
function example() {
Game
.findOne({name: /^Legend of Zelda/})
.populate('consoles')
.lean() // just return plain objects, not documents wrapped by mongoose
.exec(function(err, ocinara) {
if (err) return done(err);
console.log(
'"%s" was released for the %s on %s',
ocinara.name,
ocinara.consoles[0].name,
ocinara.released.toLocaleDateString()
);
done();
});
}
function done(err) {
if (err) console.error(err);
Console.remove(function() {
Game.remove(function() {
mongoose.disconnect();
});
});
}
+14
View File
@@ -0,0 +1,14 @@
{
"name": "promise-example",
"private": "true",
"version": "0.0.0",
"description": "deps for promise example",
"main": "promise.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"dependencies": { "async": "*" },
"repository": "",
"author": "",
"license": "BSD"
}
+15
View File
@@ -0,0 +1,15 @@
// import the necessary modules
var mongoose = require('../../lib');
var Schema = mongoose.Schema;
// create an export function to encapsulate the model creation
module.exports = function() {
// define schema
var PersonSchema = new Schema({
name: String,
age: Number,
birthday: Date
});
mongoose.model('Person', PersonSchema);
};
+94
View File
@@ -0,0 +1,94 @@
// import async to make control flow simplier
var async = require('async');
// import the rest of the normal stuff
var mongoose = require('../../lib');
require('./person.js')();
var Person = mongoose.model('Person');
// define some dummy data
var data = [
{
name: 'bill',
age: 25,
birthday: new Date().setFullYear((new Date().getFullYear() - 25))
},
{
name: 'mary',
age: 30,
birthday: new Date().setFullYear((new Date().getFullYear() - 30))
},
{
name: 'bob',
age: 21,
birthday: new Date().setFullYear((new Date().getFullYear() - 21))
},
{
name: 'lilly',
age: 26,
birthday: new Date().setFullYear((new Date().getFullYear() - 26))
},
{
name: 'alucard',
age: 1000,
birthday: new Date().setFullYear((new Date().getFullYear() - 1000))
}
];
mongoose.connect('mongodb://localhost/persons', function(err) {
if (err) {
throw err;
}
// create all of the dummy people
async.each(data, function(item, cb) {
Person.create(item, cb);
}, function(err) {
if (err) {
// handle error
}
// create a promise (get one from the query builder)
var prom = Person.find({age: {$lt: 1000}}).exec();
// add a callback on the promise. This will be called on both error and
// complete
prom.addBack(function() {
console.log('completed');
});
// add a callback that is only called on complete (success) events
prom.addCallback(function() {
console.log('Successful Completion!');
});
// add a callback that is only called on err (rejected) events
prom.addErrback(function() {
console.log('Fail Boat');
});
// you can chain things just like in the promise/A+ spec
// note: each then() is returning a new promise, so the above methods
// that we defined will all fire after the initial promise is fulfilled
prom.then(function(people) {
// just getting the stuff for the next query
var ids = people.map(function(p) {
return p._id;
});
// return the next promise
return Person.find({_id: {$nin: ids}}).exec();
}).then(function(oldest) {
console.log('Oldest person is: %s', oldest);
}).then(cleanup);
});
});
function cleanup() {
Person.remove(function() {
mongoose.disconnect();
});
}
+14
View File
@@ -0,0 +1,14 @@
{
"name": "query-builder-example",
"private": "true",
"version": "0.0.0",
"description": "deps for query builder example",
"main": "querybuilder.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"dependencies": { "async": "*" },
"repository": "",
"author": "",
"license": "BSD"
}
+15
View File
@@ -0,0 +1,15 @@
// import the necessary modules
var mongoose = require('../../lib');
var Schema = mongoose.Schema;
// create an export function to encapsulate the model creation
module.exports = function() {
// define schema
var PersonSchema = new Schema({
name: String,
age: Number,
birthday: Date
});
mongoose.model('Person', PersonSchema);
};
@@ -0,0 +1,79 @@
// import async to make control flow simplier
var async = require('async');
// import the rest of the normal stuff
var mongoose = require('../../lib');
require('./person.js')();
var Person = mongoose.model('Person');
// define some dummy data
var data = [
{
name: 'bill',
age: 25,
birthday: new Date().setFullYear((new Date().getFullYear() - 25))
},
{
name: 'mary',
age: 30,
birthday: new Date().setFullYear((new Date().getFullYear() - 30))
},
{
name: 'bob',
age: 21,
birthday: new Date().setFullYear((new Date().getFullYear() - 21))
},
{
name: 'lilly',
age: 26,
birthday: new Date().setFullYear((new Date().getFullYear() - 26))
},
{
name: 'alucard',
age: 1000,
birthday: new Date().setFullYear((new Date().getFullYear() - 1000))
}
];
mongoose.connect('mongodb://localhost/persons', function(err) {
if (err) throw err;
// create all of the dummy people
async.each(data, function(item, cb) {
Person.create(item, cb);
}, function(err) {
if (err) throw err;
// when querying data, instead of providing a callback, you can instead
// leave that off and get a query object returned
var query = Person.find({age: {$lt: 1000}});
// this allows you to continue applying modifiers to it
query.sort('birthday');
query.select('name');
// you can chain them together as well
// a full list of methods can be found:
// http://mongoosejs.com/docs/api.html#query-js
query.where('age').gt(21);
// finally, when ready to execute the query, call the exec() function
query.exec(function(err, results) {
if (err) throw err;
console.log(results);
cleanup();
});
});
});
function cleanup() {
Person.remove(function() {
mongoose.disconnect();
});
}
+14
View File
@@ -0,0 +1,14 @@
{
"name": "replica-set-example",
"private": "true",
"version": "0.0.0",
"description": "deps for replica set example",
"main": "querybuilder.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"dependencies": { "async": "*" },
"repository": "",
"author": "",
"license": "BSD"
}
+15
View File
@@ -0,0 +1,15 @@
// import the necessary modules
var mongoose = require('../../lib');
var Schema = mongoose.Schema;
// create an export function to encapsulate the model creation
module.exports = function() {
// define schema
var PersonSchema = new Schema({
name: String,
age: Number,
birthday: Date
});
mongoose.model('Person', PersonSchema);
};
@@ -0,0 +1,71 @@
// import async to make control flow simplier
var async = require('async');
// import the rest of the normal stuff
var mongoose = require('../../lib');
require('./person.js')();
var Person = mongoose.model('Person');
// define some dummy data
var data = [
{
name: 'bill',
age: 25,
birthday: new Date().setFullYear((new Date().getFullYear() - 25))
},
{
name: 'mary',
age: 30,
birthday: new Date().setFullYear((new Date().getFullYear() - 30))
},
{
name: 'bob',
age: 21,
birthday: new Date().setFullYear((new Date().getFullYear() - 21))
},
{
name: 'lilly',
age: 26,
birthday: new Date().setFullYear((new Date().getFullYear() - 26))
},
{
name: 'alucard',
age: 1000,
birthday: new Date().setFullYear((new Date().getFullYear() - 1000))
}
];
// to connect to a replica set, pass in the comma delimited uri and optionally
// any connection options such as the rs_name.
var opts = {
replSet: {rs_name: 'rs0'}
};
mongoose.connect('mongodb://localhost:27018/persons,localhost:27019,localhost:27020', opts, function(err) {
if (err) throw err;
// create all of the dummy people
async.each(data, function(item, cb) {
Person.create(item, cb);
}, function(err) {
if (err) {
// handle error
}
// create and delete some data
var prom = Person.find({age: {$lt: 1000}}).exec();
prom.then(function(people) {
console.log('young people: %s', people);
}).then(cleanup);
});
});
function cleanup() {
Person.remove(function() {
mongoose.disconnect();
});
}
+119
View File
@@ -0,0 +1,119 @@
/**
* Module dependencies.
*/
var mongoose = require('../../lib'),
Schema = mongoose.Schema;
/**
* Schema definition
*/
// recursive embedded-document schema
var Comment = new Schema();
Comment.add({
title: {
type: String,
index: true
},
date: Date,
body: String,
comments: [Comment]
});
var BlogPost = new Schema({
title: {
type: String,
index: true
},
slug: {
type: String,
lowercase: true,
trim: true
},
date: Date,
buf: Buffer,
comments: [Comment],
creator: Schema.ObjectId
});
var Person = new Schema({
name: {
first: String,
last: String
},
email: {
type: String,
required: true,
index: {
unique: true,
sparse: true
}
},
alive: Boolean
});
/**
* Accessing a specific schema type by key
*/
BlogPost.path('date')
.default(function() {
return new Date();
})
.set(function(v) {
return v === 'now' ? new Date() : v;
});
/**
* Pre hook.
*/
BlogPost.pre('save', function(next, done) {
/* global emailAuthor */
emailAuthor(done); // some async function
next();
});
/**
* Methods
*/
BlogPost.methods.findCreator = function(callback) {
return this.db.model('Person').findById(this.creator, callback);
};
BlogPost.statics.findByTitle = function(title, callback) {
return this.find({title: title}, callback);
};
BlogPost.methods.expressiveQuery = function(creator, date, callback) {
return this.find('creator', creator).where('date').gte(date).run(callback);
};
/**
* Plugins
*/
function slugGenerator(options) {
options = options || {};
var key = options.key || 'title';
return function slugGenerator(schema) {
schema.path(key).set(function(v) {
this.slug = v.toLowerCase().replace(/[^a-z0-9]/g, '').replace(/-+/g, '');
return v;
});
};
}
BlogPost.plugin(slugGenerator());
/**
* Define model.
*/
mongoose.model('BlogPost', BlogPost);
mongoose.model('Person', Person);
@@ -0,0 +1,27 @@
// modules
var mongoose = require('../../../lib');
var Schema = mongoose.Schema;
// parse json
var raw = require('./schema.json');
// create a schema
var timeSignatureSchema = Schema(raw);
// compile the model
var TimeSignature = mongoose.model('TimeSignatures', timeSignatureSchema);
// create a TimeSignature document
var threeFour = new TimeSignature({
count: 3,
unit: 4,
description: '3/4',
additive: false,
created: new Date,
links: ['http://en.wikipedia.org/wiki/Time_signature'],
user_id: '518d31a0ef32bbfa853a9814'
});
// print its description
console.log(threeFour);
@@ -0,0 +1,9 @@
{
"count": "number",
"unit": "number",
"description": "string",
"links": ["string"],
"created": "date",
"additive": "boolean",
"user_id": "ObjectId"
}
+20
View File
@@ -0,0 +1,20 @@
// import the necessary modules
var mongoose = require('../../lib');
var Schema = mongoose.Schema;
// create an export function to encapsulate the model creation
module.exports = function() {
// define schema
var PersonSchema = new Schema({
name: String,
age: Number,
birthday: Date
});
// define a static
PersonSchema.statics.findPersonByName = function(name, cb) {
this.find({name: new RegExp(name, 'i')}, cb);
};
mongoose.model('Person', PersonSchema);
};
+41
View File
@@ -0,0 +1,41 @@
var mongoose = require('../../lib');
// import the schema
require('./person.js')();
// grab the person model object
var Person = mongoose.model('Person');
// connect to a server to do a quick write / read example
mongoose.connect('mongodb://localhost/persons', function(err) {
if (err) {
throw err;
}
Person.create({name: 'bill', age: 25, birthday: new Date().setFullYear((new Date().getFullYear() - 25))},
function(err, bill) {
if (err) {
throw err;
}
console.log('People added to db: %s', bill.toString());
// using the static
Person.findPersonByName('bill', function(err, result) {
if (err) {
throw err;
}
console.log(result);
cleanup();
});
}
);
});
function cleanup() {
Person.remove(function() {
mongoose.disconnect();
});
}
+7
View File
@@ -0,0 +1,7 @@
/**
* Export lib/mongoose
*
*/
module.exports = require('./lib/');
+26
View File
@@ -0,0 +1,26 @@
/**
* ES6 Promise wrapper constructor.
*
* Promises are returned from executed queries. Example:
*
* var query = Candy.find({ bar: true });
* var promise = query.exec();
*
* DEPRECATED. Mongoose 5.0 will use native promises by default (or bluebird,
* if native promises are not present) but still
* support plugging in your own ES6-compatible promises library. Mongoose 5.0
* will **not** support mpromise.
*
* @param {Function} fn a function which will be called when the promise is resolved that accepts `fn(err, ...){}` as signature
* @api public
*/
function ES6Promise() {
throw new Error('Can\'t use ES6 promise with mpromise style constructor');
}
ES6Promise.use = function(Promise) {
ES6Promise.ES6 = Promise;
};
module.exports = ES6Promise;
+879
View File
@@ -0,0 +1,879 @@
/*!
* Module dependencies
*/
var AggregationCursor = require('./cursor/AggregationCursor');
var PromiseProvider = require('./promise_provider');
var Query = require('./query');
var eachAsync = require('./services/cursor/eachAsync');
var util = require('util');
var utils = require('./utils');
var read = Query.prototype.read;
/**
* Aggregate constructor used for building aggregation pipelines.
*
* ####Example:
*
* new Aggregate();
* new Aggregate({ $project: { a: 1, b: 1 } });
* new Aggregate({ $project: { a: 1, b: 1 } }, { $skip: 5 });
* new Aggregate([{ $project: { a: 1, b: 1 } }, { $skip: 5 }]);
*
* Returned when calling Model.aggregate().
*
* ####Example:
*
* Model
* .aggregate({ $match: { age: { $gte: 21 }}})
* .unwind('tags')
* .exec(callback)
*
* ####Note:
*
* - The documents returned are plain javascript objects, not mongoose documents (since any shape of document can be returned).
* - Requires MongoDB >= 2.1
* - Mongoose does **not** cast pipeline stages. `new Aggregate({ $match: { _id: '00000000000000000000000a' } });` will not work unless `_id` is a string in the database. Use `new Aggregate({ $match: { _id: mongoose.Types.ObjectId('00000000000000000000000a') } });` instead.
*
* @see MongoDB http://docs.mongodb.org/manual/applications/aggregation/
* @see driver http://mongodb.github.com/node-mongodb-native/api-generated/collection.html#aggregate
* @param {Object|Array} [ops] aggregation operator(s) or operator array
* @api public
*/
function Aggregate() {
this._pipeline = [];
this._model = undefined;
this.options = {};
if (arguments.length === 1 && util.isArray(arguments[0])) {
this.append.apply(this, arguments[0]);
} else {
this.append.apply(this, arguments);
}
}
/**
* Binds this aggregate to a model.
*
* @param {Model} model the model to which the aggregate is to be bound
* @return {Aggregate}
* @api public
*/
Aggregate.prototype.model = function(model) {
this._model = model;
if (model.schema != null) {
if (this.options.readPreference == null &&
model.schema.options.read != null) {
this.options.readPreference = model.schema.options.read;
}
if (this.options.collation == null &&
model.schema.options.collation != null) {
this.options.collation = model.schema.options.collation;
}
}
return this;
};
/**
* Appends new operators to this aggregate pipeline
*
* ####Examples:
*
* aggregate.append({ $project: { field: 1 }}, { $limit: 2 });
*
* // or pass an array
* var pipeline = [{ $match: { daw: 'Logic Audio X' }} ];
* aggregate.append(pipeline);
*
* @param {Object} ops operator(s) to append
* @return {Aggregate}
* @api public
*/
Aggregate.prototype.append = function() {
var args = (arguments.length === 1 && util.isArray(arguments[0]))
? arguments[0]
: utils.args(arguments);
if (!args.every(isOperator)) {
throw new Error('Arguments must be aggregate pipeline operators');
}
this._pipeline = this._pipeline.concat(args);
return this;
};
/**
* Appends a new $addFields operator to this aggregate pipeline.
* Requires MongoDB v3.4+ to work
*
* ####Examples:
*
* // adding new fields based on existing fields
* aggregate.addFields({
* newField: '$b.nested'
* , plusTen: { $add: ['$val', 10]}
* , sub: {
* name: '$a'
* }
* })
*
* // etc
* aggregate.addFields({ salary_k: { $divide: [ "$salary", 1000 ] } });
*
* @param {Object} arg field specification
* @see $addFields https://docs.mongodb.com/manual/reference/operator/aggregation/addFields/
* @return {Aggregate}
* @api public
*/
Aggregate.prototype.addFields = function(arg) {
var fields = {};
if (typeof arg === 'object' && !util.isArray(arg)) {
Object.keys(arg).forEach(function(field) {
fields[field] = arg[field];
});
} else {
throw new Error('Invalid addFields() argument. Must be an object');
}
return this.append({$addFields: fields});
};
/**
* Appends a new $project operator to this aggregate pipeline.
*
* Mongoose query [selection syntax](#query_Query-select) is also supported.
*
* ####Examples:
*
* // include a, include b, exclude _id
* aggregate.project("a b -_id");
*
* // or you may use object notation, useful when
* // you have keys already prefixed with a "-"
* aggregate.project({a: 1, b: 1, _id: 0});
*
* // reshaping documents
* aggregate.project({
* newField: '$b.nested'
* , plusTen: { $add: ['$val', 10]}
* , sub: {
* name: '$a'
* }
* })
*
* // etc
* aggregate.project({ salary_k: { $divide: [ "$salary", 1000 ] } });
*
* @param {Object|String} arg field specification
* @see projection http://docs.mongodb.org/manual/reference/aggregation/project/
* @return {Aggregate}
* @api public
*/
Aggregate.prototype.project = function(arg) {
var fields = {};
if (typeof arg === 'object' && !util.isArray(arg)) {
Object.keys(arg).forEach(function(field) {
fields[field] = arg[field];
});
} else if (arguments.length === 1 && typeof arg === 'string') {
arg.split(/\s+/).forEach(function(field) {
if (!field) {
return;
}
var include = field[0] === '-' ? 0 : 1;
if (include === 0) {
field = field.substring(1);
}
fields[field] = include;
});
} else {
throw new Error('Invalid project() argument. Must be string or object');
}
return this.append({$project: fields});
};
/**
* Appends a new custom $group operator to this aggregate pipeline.
*
* ####Examples:
*
* aggregate.group({ _id: "$department" });
*
* @see $group http://docs.mongodb.org/manual/reference/aggregation/group/
* @method group
* @memberOf Aggregate
* @param {Object} arg $group operator contents
* @return {Aggregate}
* @api public
*/
/**
* Appends a new custom $match operator to this aggregate pipeline.
*
* ####Examples:
*
* aggregate.match({ department: { $in: [ "sales", "engineering" ] } });
*
* @see $match http://docs.mongodb.org/manual/reference/aggregation/match/
* @method match
* @memberOf Aggregate
* @param {Object} arg $match operator contents
* @return {Aggregate}
* @api public
*/
/**
* Appends a new $skip operator to this aggregate pipeline.
*
* ####Examples:
*
* aggregate.skip(10);
*
* @see $skip http://docs.mongodb.org/manual/reference/aggregation/skip/
* @method skip
* @memberOf Aggregate
* @param {Number} num number of records to skip before next stage
* @return {Aggregate}
* @api public
*/
/**
* Appends a new $limit operator to this aggregate pipeline.
*
* ####Examples:
*
* aggregate.limit(10);
*
* @see $limit http://docs.mongodb.org/manual/reference/aggregation/limit/
* @method limit
* @memberOf Aggregate
* @param {Number} num maximum number of records to pass to the next stage
* @return {Aggregate}
* @api public
*/
/**
* Appends a new $geoNear operator to this aggregate pipeline.
*
* ####NOTE:
*
* **MUST** be used as the first operator in the pipeline.
*
* ####Examples:
*
* aggregate.near({
* near: [40.724, -73.997],
* distanceField: "dist.calculated", // required
* maxDistance: 0.008,
* query: { type: "public" },
* includeLocs: "dist.location",
* uniqueDocs: true,
* num: 5
* });
*
* @see $geoNear http://docs.mongodb.org/manual/reference/aggregation/geoNear/
* @method near
* @memberOf Aggregate
* @param {Object} parameters
* @return {Aggregate}
* @api public
*/
Aggregate.prototype.near = function(arg) {
var op = {};
op.$geoNear = arg;
return this.append(op);
};
/*!
* define methods
*/
'group match skip limit out'.split(' ').forEach(function($operator) {
Aggregate.prototype[$operator] = function(arg) {
var op = {};
op['$' + $operator] = arg;
return this.append(op);
};
});
/**
* Appends new custom $unwind operator(s) to this aggregate pipeline.
*
* Note that the `$unwind` operator requires the path name to start with '$'.
* Mongoose will prepend '$' if the specified field doesn't start '$'.
*
* ####Examples:
*
* aggregate.unwind("tags");
* aggregate.unwind("a", "b", "c");
*
* @see $unwind http://docs.mongodb.org/manual/reference/aggregation/unwind/
* @param {String} fields the field(s) to unwind
* @return {Aggregate}
* @api public
*/
Aggregate.prototype.unwind = function() {
var args = utils.args(arguments);
var res = [];
for (var i = 0; i < args.length; ++i) {
var arg = args[i];
if (arg && typeof arg === 'object') {
res.push({ $unwind: arg });
} else if (typeof arg === 'string') {
res.push({
$unwind: (arg && arg.charAt(0) === '$') ? arg : '$' + arg
});
} else {
throw new Error('Invalid arg "' + arg + '" to unwind(), ' +
'must be string or object');
}
}
return this.append.apply(this, res);
};
/**
* Appends new custom $lookup operator(s) to this aggregate pipeline.
*
* ####Examples:
*
* aggregate.lookup({ from: 'users', localField: 'userId', foreignField: '_id', as: 'users' });
*
* @see $lookup https://docs.mongodb.org/manual/reference/operator/aggregation/lookup/#pipe._S_lookup
* @param {Object} options to $lookup as described in the above link
* @return {Aggregate}
* @api public
*/
Aggregate.prototype.lookup = function(options) {
return this.append({$lookup: options});
};
/**
* Appends new custom $graphLookup operator(s) to this aggregate pipeline, performing a recursive search on a collection.
*
* Note that graphLookup can only consume at most 100MB of memory, and does not allow disk use even if `{ allowDiskUse: true }` is specified.
*
* #### Examples:
* // Suppose we have a collection of courses, where a document might look like `{ _id: 0, name: 'Calculus', prerequisite: 'Trigonometry'}` and `{ _id: 0, name: 'Trigonometry', prerequisite: 'Algebra' }`
* aggregate.graphLookup({ from: 'courses', startWith: '$prerequisite', connectFromField: 'prerequisite', connectToField: 'name', as: 'prerequisites', maxDepth: 3 }) // this will recursively search the 'courses' collection up to 3 prerequisites
*
* @see $graphLookup https://docs.mongodb.com/manual/reference/operator/aggregation/graphLookup/#pipe._S_graphLookup
* @param {Object} options to $graphLookup as described in the above link
* @return {Aggregate}
* @api public
*/
Aggregate.prototype.graphLookup = function(options) {
var cloneOptions = {};
if (options) {
if (!utils.isObject(options)) {
throw new TypeError('Invalid graphLookup() argument. Must be an object.');
}
utils.mergeClone(cloneOptions, options);
var startWith = cloneOptions.startWith;
if (startWith && typeof startWith === 'string') {
cloneOptions.startWith = cloneOptions.startWith.charAt(0) === '$' ?
cloneOptions.startWith :
'$' + cloneOptions.startWith;
}
}
return this.append({ $graphLookup: cloneOptions });
};
/**
* Appepnds new custom $sample operator(s) to this aggregate pipeline.
*
* ####Examples:
*
* aggregate.sample(3); // Add a pipeline that picks 3 random documents
*
* @see $sample https://docs.mongodb.org/manual/reference/operator/aggregation/sample/#pipe._S_sample
* @param {Number} size number of random documents to pick
* @return {Aggregate}
* @api public
*/
Aggregate.prototype.sample = function(size) {
return this.append({$sample: {size: size}});
};
/**
* Appends a new $sort operator to this aggregate pipeline.
*
* If an object is passed, values allowed are `asc`, `desc`, `ascending`, `descending`, `1`, and `-1`.
*
* If a string is passed, it must be a space delimited list of path names. The sort order of each path is ascending unless the path name is prefixed with `-` which will be treated as descending.
*
* ####Examples:
*
* // these are equivalent
* aggregate.sort({ field: 'asc', test: -1 });
* aggregate.sort('field -test');
*
* @see $sort http://docs.mongodb.org/manual/reference/aggregation/sort/
* @param {Object|String} arg
* @return {Aggregate} this
* @api public
*/
Aggregate.prototype.sort = function(arg) {
// TODO refactor to reuse the query builder logic
var sort = {};
if (arg.constructor.name === 'Object') {
var desc = ['desc', 'descending', -1];
Object.keys(arg).forEach(function(field) {
// If sorting by text score, skip coercing into 1/-1
if (arg[field] instanceof Object && arg[field].$meta) {
sort[field] = arg[field];
return;
}
sort[field] = desc.indexOf(arg[field]) === -1 ? 1 : -1;
});
} else if (arguments.length === 1 && typeof arg === 'string') {
arg.split(/\s+/).forEach(function(field) {
if (!field) {
return;
}
var ascend = field[0] === '-' ? -1 : 1;
if (ascend === -1) {
field = field.substring(1);
}
sort[field] = ascend;
});
} else {
throw new TypeError('Invalid sort() argument. Must be a string or object.');
}
return this.append({$sort: sort});
};
/**
* Sets the readPreference option for the aggregation query.
*
* ####Example:
*
* Model.aggregate(..).read('primaryPreferred').exec(callback)
*
* @param {String} pref one of the listed preference options or their aliases
* @param {Array} [tags] optional tags for this query
* @see mongodb http://docs.mongodb.org/manual/applications/replication/#read-preference
* @see driver http://mongodb.github.com/node-mongodb-native/driver-articles/anintroductionto1_1and2_2.html#read-preferences
*/
Aggregate.prototype.read = function(pref, tags) {
if (!this.options) {
this.options = {};
}
read.call(this, pref, tags);
return this;
};
/**
* Execute the aggregation with explain
*
* ####Example:
*
* Model.aggregate(..).explain(callback)
*
* @param {Function} callback
* @return {Promise}
*/
Aggregate.prototype.explain = function(callback) {
var _this = this;
var Promise = PromiseProvider.get();
return new Promise.ES6(function(resolve, reject) {
if (!_this._pipeline.length) {
var err = new Error('Aggregate has empty pipeline');
if (callback) {
callback(err);
}
reject(err);
return;
}
prepareDiscriminatorPipeline(_this);
_this._model
.collection
.aggregate(_this._pipeline, _this.options || {})
.explain(function(error, result) {
if (error) {
if (callback) {
callback(error);
}
reject(error);
return;
}
if (callback) {
callback(null, result);
}
resolve(result);
});
});
};
/**
* Sets the allowDiskUse option for the aggregation query (ignored for < 2.6.0)
*
* ####Example:
*
* Model.aggregate(..).allowDiskUse(true).exec(callback)
*
* @param {Boolean} value Should tell server it can use hard drive to store data during aggregation.
* @param {Array} [tags] optional tags for this query
* @see mongodb http://docs.mongodb.org/manual/reference/command/aggregate/
*/
Aggregate.prototype.allowDiskUse = function(value) {
this.options.allowDiskUse = value;
return this;
};
/**
* Lets you set arbitrary options, for middleware or plugins.
*
* ####Example:
*
* var agg = Model.aggregate(..).option({ allowDiskUse: true }); // Set the `allowDiskUse` option
* agg.options; // `{ allowDiskUse: true }`
*
* @param {Object} options keys to merge into current options
* @param [options.maxTimeMS] number limits the time this aggregation will run, see [MongoDB docs on `maxTimeMS`](https://docs.mongodb.com/manual/reference/operator/meta/maxTimeMS/)
* @param [options.allowDiskUse] boolean if true, the MongoDB server will use the hard drive to store data during this aggregation
* @param [options.collation] object see [`Aggregate.prototype.collation()`](./docs/api.html#aggregate_Aggregate-collation)
* @see mongodb http://docs.mongodb.org/manual/reference/command/aggregate/
* @return {Aggregate} this
* @api public
*/
Aggregate.prototype.option = function(value) {
for (var key in value) {
this.options[key] = value[key];
}
return this;
};
/**
* Sets the cursor option option for the aggregation query (ignored for < 2.6.0).
* Note the different syntax below: .exec() returns a cursor object, and no callback
* is necessary.
*
* ####Example:
*
* var cursor = Model.aggregate(..).cursor({ batchSize: 1000, useMongooseAggCursor: true }).exec();
* cursor.each(function(error, doc) {
* // use doc
* });
*
* @param {Object} options
* @param {Number} options.batchSize set the cursor batch size
* @param {Boolean} [options.useMongooseAggCursor] use experimental mongoose-specific aggregation cursor (for `eachAsync()` and other query cursor semantics)
* @see mongodb http://mongodb.github.io/node-mongodb-native/2.0/api/AggregationCursor.html
*/
Aggregate.prototype.cursor = function(options) {
if (!this.options) {
this.options = {};
}
this.options.cursor = options || {};
return this;
};
/**
* Adds a [cursor flag](http://mongodb.github.io/node-mongodb-native/2.2/api/Cursor.html#addCursorFlag)
*
* ####Example:
*
* Model.aggregate(..).addCursorFlag('noCursorTimeout', true).exec();
*
* @param {String} flag
* @param {Boolean} value
* @see mongodb http://mongodb.github.io/node-mongodb-native/2.2/api/Cursor.html#addCursorFlag
*/
Aggregate.prototype.addCursorFlag = function(flag, value) {
if (!this.options) {
this.options = {};
}
this.options[flag] = value;
return this;
};
/**
* Adds a collation
*
* ####Example:
*
* Model.aggregate(..).collation({ locale: 'en_US', strength: 1 }).exec();
*
* @param {Object} collation options
* @see mongodb http://mongodb.github.io/node-mongodb-native/2.2/api/Collection.html#aggregate
*/
Aggregate.prototype.collation = function(collation) {
if (!this.options) {
this.options = {};
}
this.options.collation = collation;
return this;
};
/**
* Combines multiple aggregation pipelines.
*
* ####Example:
* Model.aggregate(...)
* .facet({
* books: [{ groupBy: '$author' }],
* price: [{ $bucketAuto: { groupBy: '$price', buckets: 2 } }]
* })
* .exec();
*
* // Output: { books: [...], price: [{...}, {...}] }
*
* @param {Object} facet options
* @return {Aggregate} this
* @see $facet https://docs.mongodb.com/v3.4/reference/operator/aggregation/facet/
* @api public
*/
Aggregate.prototype.facet = function(options) {
return this.append({$facet: options});
};
/**
* Returns the current pipeline
*
* ####Example:
*
* MyModel.aggregate().match({ test: 1 }).pipeline(); // [{ $match: { test: 1 } }]
*
* @return {Array}
* @api public
*/
Aggregate.prototype.pipeline = function() {
return this._pipeline;
};
/**
* Executes the aggregate pipeline on the currently bound Model.
*
* ####Example:
*
* aggregate.exec(callback);
*
* // Because a promise is returned, the `callback` is optional.
* var promise = aggregate.exec();
* promise.then(..);
*
* @see Promise #promise_Promise
* @param {Function} [callback]
* @return {Promise}
* @api public
*/
Aggregate.prototype.exec = function(callback) {
if (!this._model) {
throw new Error('Aggregate not bound to any Model');
}
var _this = this;
var model = this._model;
var Promise = PromiseProvider.get();
var options = utils.clone(this.options || {});
var pipeline = this._pipeline;
var collection = this._model.collection;
if (options && options.cursor) {
if (options.cursor.async) {
delete options.cursor.async;
return new Promise.ES6(function(resolve) {
if (!collection.buffer) {
process.nextTick(function() {
var cursor = collection.aggregate(pipeline, options);
decorateCursor(cursor);
resolve(cursor);
callback && callback(null, cursor);
});
return;
}
collection.emitter.once('queue', function() {
var cursor = collection.aggregate(pipeline, options);
decorateCursor(cursor);
resolve(cursor);
callback && callback(null, cursor);
});
});
} else if (options.cursor.useMongooseAggCursor) {
delete options.cursor.useMongooseAggCursor;
return new AggregationCursor(this);
}
var cursor = collection.aggregate(pipeline, options);
decorateCursor(cursor);
return cursor;
}
return new Promise.ES6(function(resolve, reject) {
if (!pipeline.length) {
var err = new Error('Aggregate has empty pipeline');
if (callback) {
callback(err);
}
reject(err);
return;
}
prepareDiscriminatorPipeline(_this);
model.hooks.execPre('aggregate', _this, function(error) {
if (error) {
var _opts = { error: error };
return model.hooks.execPost('aggregate', _this, [null], _opts, function(error) {
if (callback) {
callback(error);
}
reject(error);
});
}
collection.aggregate(pipeline, options, function(error, result) {
var _opts = { error: error };
model.hooks.execPost('aggregate', _this, [result], _opts, function(error, result) {
if (error) {
if (callback) {
callback(error);
}
reject(error);
return;
}
if (callback) {
callback(null, result);
}
resolve(result);
});
});
});
});
};
/*!
* Add `eachAsync()` to aggregation cursors
*/
function decorateCursor(cursor) {
cursor.eachAsync = function(fn, opts, callback) {
if (typeof opts === 'function') {
callback = opts;
opts = {};
}
opts = opts || {};
return eachAsync(function(cb) { return cursor.next(cb); }, fn, opts, callback);
};
}
/**
* Provides promise for aggregate.
*
* ####Example:
*
* Model.aggregate(..).then(successCallback, errorCallback);
*
* @see Promise #promise_Promise
* @param {Function} [resolve] successCallback
* @param {Function} [reject] errorCallback
* @return {Promise}
*/
Aggregate.prototype.then = function(resolve, reject) {
return this.exec().then(resolve, reject);
};
/*!
* Helpers
*/
/**
* Checks whether an object is likely a pipeline operator
*
* @param {Object} obj object to check
* @return {Boolean}
* @api private
*/
function isOperator(obj) {
var k;
if (typeof obj !== 'object') {
return false;
}
k = Object.keys(obj);
return k.length === 1 && k
.some(function(key) {
return key[0] === '$';
});
}
/*!
* Adds the appropriate `$match` pipeline step to the top of an aggregate's
* pipeline, should it's model is a non-root discriminator type. This is
* analogous to the `prepareDiscriminatorCriteria` function in `lib/query.js`.
*
* @param {Aggregate} aggregate Aggregate to prepare
*/
Aggregate._prepareDiscriminatorPipeline = prepareDiscriminatorPipeline;
function prepareDiscriminatorPipeline(aggregate) {
var schema = aggregate._model.schema,
discriminatorMapping = schema && schema.discriminatorMapping;
if (discriminatorMapping && !discriminatorMapping.isRoot) {
var originalPipeline = aggregate._pipeline,
discriminatorKey = discriminatorMapping.key,
discriminatorValue = discriminatorMapping.value;
// If the first pipeline stage is a match and it doesn't specify a `__t`
// key, add the discriminator key to it. This allows for potential
// aggregation query optimizations not to be disturbed by this feature.
if (originalPipeline[0] && originalPipeline[0].$match && !originalPipeline[0].$match[discriminatorKey]) {
originalPipeline[0].$match[discriminatorKey] = discriminatorValue;
// `originalPipeline` is a ref, so there's no need for
// aggregate._pipeline = originalPipeline
} else if (originalPipeline[0] && originalPipeline[0].$geoNear) {
originalPipeline[0].$geoNear.query =
originalPipeline[0].$geoNear.query || {};
originalPipeline[0].$geoNear.query[discriminatorKey] = discriminatorValue;
} else {
var match = {};
match[discriminatorKey] = discriminatorValue;
aggregate._pipeline.unshift({ $match: match });
}
}
}
/*!
* Exports
*/
module.exports = Aggregate;
+129
View File
@@ -0,0 +1,129 @@
/* eslint-env browser */
var DocumentProvider = require('./document_provider.js');
var PromiseProvider = require('./promise_provider');
DocumentProvider.setBrowser(true);
/**
* The Mongoose [Promise](#promise_Promise) constructor.
*
* @method Promise
* @api public
*/
Object.defineProperty(exports, 'Promise', {
get: function() {
return PromiseProvider.get();
},
set: function(lib) {
PromiseProvider.set(lib);
}
});
/**
* Storage layer for mongoose promises
*
* @method PromiseProvider
* @api public
*/
exports.PromiseProvider = PromiseProvider;
/**
* The [MongooseError](#error_MongooseError) constructor.
*
* @method Error
* @api public
*/
exports.Error = require('./error');
/**
* The Mongoose [Schema](#schema_Schema) constructor
*
* ####Example:
*
* var mongoose = require('mongoose');
* var Schema = mongoose.Schema;
* var CatSchema = new Schema(..);
*
* @method Schema
* @api public
*/
exports.Schema = require('./schema');
/**
* The various Mongoose Types.
*
* ####Example:
*
* var mongoose = require('mongoose');
* var array = mongoose.Types.Array;
*
* ####Types:
*
* - [ObjectId](#types-objectid-js)
* - [Buffer](#types-buffer-js)
* - [SubDocument](#types-embedded-js)
* - [Array](#types-array-js)
* - [DocumentArray](#types-documentarray-js)
*
* Using this exposed access to the `ObjectId` type, we can construct ids on demand.
*
* var ObjectId = mongoose.Types.ObjectId;
* var id1 = new ObjectId;
*
* @property Types
* @api public
*/
exports.Types = require('./types');
/**
* The Mongoose [VirtualType](#virtualtype_VirtualType) constructor
*
* @method VirtualType
* @api public
*/
exports.VirtualType = require('./virtualtype');
/**
* The various Mongoose SchemaTypes.
*
* ####Note:
*
* _Alias of mongoose.Schema.Types for backwards compatibility._
*
* @property SchemaTypes
* @see Schema.SchemaTypes #schema_Schema.Types
* @api public
*/
exports.SchemaType = require('./schematype.js');
/**
* Internal utils
*
* @property utils
* @api private
*/
exports.utils = require('./utils.js');
/**
* The Mongoose browser [Document](#document-js) constructor.
*
* @method Document
* @api public
*/
exports.Document = DocumentProvider();
/*!
* Module exports.
*/
if (typeof window !== 'undefined') {
window.mongoose = module.exports;
window.Buffer = Buffer;
}
+294
View File
@@ -0,0 +1,294 @@
/*!
* Module dependencies.
*/
var NodeJSDocument = require('./document');
var EventEmitter = require('events').EventEmitter;
var MongooseError = require('./error');
var Schema = require('./schema');
var ObjectId = require('./types/objectid');
var utils = require('./utils');
var ValidationError = MongooseError.ValidationError;
var InternalCache = require('./internal');
var PromiseProvider = require('./promise_provider');
var VersionError = require('./error').VersionError;
var Embedded;
/**
* Document constructor.
*
* @param {Object} obj the values to set
* @param {Object} [fields] optional object containing the fields which were selected in the query returning this document and any populated paths data
* @param {Boolean} [skipId] bool, should we auto create an ObjectId _id
* @inherits NodeJS EventEmitter http://nodejs.org/api/events.html#events_class_events_eventemitter
* @event `init`: Emitted on a document after it has was retrieved from the db and fully hydrated by Mongoose.
* @event `save`: Emitted when the document is successfully saved
* @api private
*/
function Document(obj, schema, fields, skipId, skipInit) {
if (!(this instanceof Document)) {
return new Document(obj, schema, fields, skipId, skipInit);
}
if (utils.isObject(schema) && !schema.instanceOfSchema) {
schema = new Schema(schema);
}
// When creating EmbeddedDocument, it already has the schema and he doesn't need the _id
schema = this.schema || schema;
// Generate ObjectId if it is missing, but it requires a scheme
if (!this.schema && schema.options._id) {
obj = obj || {};
if (obj._id === undefined) {
obj._id = new ObjectId();
}
}
if (!schema) {
throw new MongooseError.MissingSchemaError();
}
this.$__setSchema(schema);
this.$__ = new InternalCache;
this.$__.emitter = new EventEmitter();
this.isNew = true;
this.errors = undefined;
if (typeof fields === 'boolean') {
this.$__.strictMode = fields;
fields = undefined;
} else {
this.$__.strictMode = this.schema.options && this.schema.options.strict;
this.$__.selected = fields;
}
var required = this.schema.requiredPaths();
for (var i = 0; i < required.length; ++i) {
this.$__.activePaths.require(required[i]);
}
this.$__.emitter.setMaxListeners(0);
this._doc = this.$__buildDoc(obj, fields, skipId);
if (!skipInit && obj) {
this.init(obj);
}
this.$__registerHooksFromSchema();
// apply methods
for (var m in schema.methods) {
this[m] = schema.methods[m];
}
// apply statics
for (var s in schema.statics) {
this[s] = schema.statics[s];
}
}
/*!
* Inherit from the NodeJS document
*/
Document.prototype = Object.create(NodeJSDocument.prototype);
Document.prototype.constructor = Document;
/*!
* Browser doc exposes the event emitter API
*/
Document.$emitter = new EventEmitter();
utils.each(
['on', 'once', 'emit', 'listeners', 'removeListener', 'setMaxListeners',
'removeAllListeners', 'addListener'],
function(emitterFn) {
Document[emitterFn] = function() {
return Document.$emitter[emitterFn].apply(Document.$emitter, arguments);
};
});
/*!
* Executes methods queued from the Schema definition
*
* @api private
* @method $__registerHooksFromSchema
* @deprecated
* @memberOf Document
*/
Document.prototype.$__registerHooksFromSchema = function() {
Embedded = Embedded || require('./types/embedded');
var Promise = PromiseProvider.get();
var _this = this;
var q = _this.schema && _this.schema.callQueue;
var toWrapEl;
var len;
var i;
var j;
var pointCut;
var keys;
if (!q.length) {
return _this;
}
// we are only interested in 'pre' hooks, and group by point-cut
var toWrap = { post: [] };
var pair;
for (i = 0; i < q.length; ++i) {
pair = q[i];
if (pair[0] !== 'pre' && pair[0] !== 'post' && pair[0] !== 'on') {
_this[pair[0]].apply(_this, pair[1]);
continue;
}
var args = [].slice.call(pair[1]);
pointCut = pair[0] === 'on' ? 'post' : args[0];
if (!(pointCut in toWrap)) {
toWrap[pointCut] = {post: [], pre: []};
}
if (pair[0] === 'post') {
toWrap[pointCut].post.push(args);
} else if (pair[0] === 'on') {
toWrap[pointCut].push(args);
} else {
toWrap[pointCut].pre.push(args);
}
}
// 'post' hooks are simpler
len = toWrap.post.length;
toWrap.post.forEach(function(args) {
_this.on.apply(_this, args);
});
delete toWrap.post;
// 'init' should be synchronous on subdocuments
if (toWrap.init && _this instanceof Embedded) {
if (toWrap.init.pre) {
toWrap.init.pre.forEach(function(args) {
_this.$pre.apply(_this, args);
});
}
if (toWrap.init.post) {
toWrap.init.post.forEach(function(args) {
_this.$post.apply(_this, args);
});
}
delete toWrap.init;
} else if (toWrap.set) {
// Set hooks also need to be sync re: gh-3479
if (toWrap.set.pre) {
toWrap.set.pre.forEach(function(args) {
_this.$pre.apply(_this, args);
});
}
if (toWrap.set.post) {
toWrap.set.post.forEach(function(args) {
_this.$post.apply(_this, args);
});
}
delete toWrap.set;
}
keys = Object.keys(toWrap);
len = keys.length;
for (i = 0; i < len; ++i) {
pointCut = keys[i];
// this is so we can wrap everything into a promise;
var newName = ('$__original_' + pointCut);
if (!_this[pointCut]) {
continue;
}
if (_this[pointCut].$isWrapped) {
continue;
}
_this[newName] = _this[pointCut];
_this[pointCut] = (function(_newName) {
return function wrappedPointCut() {
var args = [].slice.call(arguments);
var lastArg = args.pop();
var fn;
var originalError = new Error();
var $results;
if (lastArg && typeof lastArg !== 'function') {
args.push(lastArg);
} else {
fn = lastArg;
}
var promise = new Promise.ES6(function(resolve, reject) {
args.push(function(error) {
if (error) {
// gh-2633: since VersionError is very generic, take the
// stack trace of the original save() function call rather
// than the async trace
if (error instanceof VersionError) {
error.stack = originalError.stack;
}
_this.$__handleReject(error);
reject(error);
return;
}
// There may be multiple results and promise libs other than
// mpromise don't support passing multiple values to `resolve()`
$results = Array.prototype.slice.call(arguments, 1);
resolve.apply(promise, $results);
});
_this[_newName].apply(_this, args);
});
if (fn) {
if (_this.constructor.$wrapCallback) {
fn = _this.constructor.$wrapCallback(fn);
}
return promise.then(
function() {
process.nextTick(function() {
fn.apply(null, [null].concat($results));
});
},
function(error) {
process.nextTick(function() {
fn(error);
});
});
}
return promise;
};
})(newName);
_this[pointCut].$isWrapped = true;
toWrapEl = toWrap[pointCut];
var _len = toWrapEl.pre.length;
args;
for (j = 0; j < _len; ++j) {
args = toWrapEl.pre[j];
args[0] = newName;
_this.$pre.apply(_this, args);
}
_len = toWrapEl.post.length;
for (j = 0; j < _len; ++j) {
args = toWrapEl.post[j];
args[0] = newName;
_this.$post.apply(_this, args);
}
}
return _this;
};
/*!
* Module exports.
*/
Document.ValidationError = ValidationError;
module.exports = exports = Document;
+302
View File
@@ -0,0 +1,302 @@
/*!
* Module dependencies.
*/
var StrictModeError = require('./error/strict');
var Types = require('./schema/index');
var util = require('util');
var utils = require('./utils');
var ALLOWED_GEOWITHIN_GEOJSON_TYPES = ['Polygon', 'MultiPolygon'];
/**
* Handles internal casting for query filters.
*
* @param {Schema} schema
* @param {Object} obj Object to cast
* @param {Object} options the query options
* @param {Query} context passed to setters
* @api private
*/
module.exports = function cast(schema, obj, options, context) {
if (Array.isArray(obj)) {
throw new Error('Query filter must be an object, got an array ', util.inspect(obj));
}
var paths = Object.keys(obj);
var i = paths.length;
var _keys;
var any$conditionals;
var schematype;
var nested;
var path;
var type;
var val;
while (i--) {
path = paths[i];
val = obj[path];
if (path === '$or' || path === '$nor' || path === '$and') {
var k = val.length;
while (k--) {
val[k] = cast(schema, val[k], options, context);
}
} else if (path === '$where') {
type = typeof val;
if (type !== 'string' && type !== 'function') {
throw new Error('Must have a string or function for $where');
}
if (type === 'function') {
obj[path] = val.toString();
}
continue;
} else if (path === '$elemMatch') {
val = cast(schema, val, options, context);
} else {
if (!schema) {
// no casting for Mixed types
continue;
}
schematype = schema.path(path);
if (!schematype) {
// Handle potential embedded array queries
var split = path.split('.'),
j = split.length,
pathFirstHalf,
pathLastHalf,
remainingConds;
// Find the part of the var path that is a path of the Schema
while (j--) {
pathFirstHalf = split.slice(0, j).join('.');
schematype = schema.path(pathFirstHalf);
if (schematype) {
break;
}
}
// If a substring of the input path resolves to an actual real path...
if (schematype) {
// Apply the casting; similar code for $elemMatch in schema/array.js
if (schematype.caster && schematype.caster.schema) {
remainingConds = {};
pathLastHalf = split.slice(j).join('.');
remainingConds[pathLastHalf] = val;
obj[path] = cast(schematype.caster.schema, remainingConds, options, context)[pathLastHalf];
} else {
obj[path] = val;
}
continue;
}
if (utils.isObject(val)) {
// handle geo schemas that use object notation
// { loc: { long: Number, lat: Number }
var geo = '';
if (val.$near) {
geo = '$near';
} else if (val.$nearSphere) {
geo = '$nearSphere';
} else if (val.$within) {
geo = '$within';
} else if (val.$geoIntersects) {
geo = '$geoIntersects';
} else if (val.$geoWithin) {
geo = '$geoWithin';
}
if (geo) {
var numbertype = new Types.Number('__QueryCasting__');
var value = val[geo];
if (val.$maxDistance != null) {
val.$maxDistance = numbertype.castForQueryWrapper({
val: val.$maxDistance,
context: context
});
}
if (val.$minDistance != null) {
val.$minDistance = numbertype.castForQueryWrapper({
val: val.$minDistance,
context: context
});
}
if (geo === '$within') {
var withinType = value.$center
|| value.$centerSphere
|| value.$box
|| value.$polygon;
if (!withinType) {
throw new Error('Bad $within paramater: ' + JSON.stringify(val));
}
value = withinType;
} else if (geo === '$near' &&
typeof value.type === 'string' && Array.isArray(value.coordinates)) {
// geojson; cast the coordinates
value = value.coordinates;
} else if ((geo === '$near' || geo === '$nearSphere' || geo === '$geoIntersects') &&
value.$geometry && typeof value.$geometry.type === 'string' &&
Array.isArray(value.$geometry.coordinates)) {
if (value.$maxDistance != null) {
value.$maxDistance = numbertype.castForQueryWrapper({
val: value.$maxDistance,
context: context
});
}
if (value.$minDistance != null) {
value.$minDistance = numbertype.castForQueryWrapper({
val: value.$minDistance,
context: context
});
}
if (utils.isMongooseObject(value.$geometry)) {
value.$geometry = value.$geometry.toObject({
transform: false,
virtuals: false
});
}
value = value.$geometry.coordinates;
} else if (geo === '$geoWithin') {
if (value.$geometry) {
if (utils.isMongooseObject(value.$geometry)) {
value.$geometry = value.$geometry.toObject({ virtuals: false });
}
var geoWithinType = value.$geometry.type;
if (ALLOWED_GEOWITHIN_GEOJSON_TYPES.indexOf(geoWithinType) === -1) {
throw new Error('Invalid geoJSON type for $geoWithin "' +
geoWithinType + '", must be "Polygon" or "MultiPolygon"');
}
value = value.$geometry.coordinates;
} else {
value = value.$box || value.$polygon || value.$center ||
value.$centerSphere;
if (utils.isMongooseObject(value)) {
value = value.toObject({ virtuals: false });
}
}
}
_cast(value, numbertype, context);
continue;
}
}
if (options && options.upsert && options.strict && !schema.nested[path]) {
if (options.strict === 'throw') {
throw new StrictModeError(path);
}
throw new StrictModeError(path, 'Path "' + path + '" is not in ' +
'schema, strict mode is `true`, and upsert is `true`.');
} else if (options && options.strictQuery === 'throw') {
throw new StrictModeError(path, 'Path "' + path + '" is not in ' +
'schema and strictQuery is true.');
}
} else if (val === null || val === undefined) {
obj[path] = null;
continue;
} else if (val.constructor.name === 'Object') {
any$conditionals = Object.keys(val).some(function(k) {
return k.charAt(0) === '$' && k !== '$id' && k !== '$ref';
});
if (!any$conditionals) {
obj[path] = schematype.castForQueryWrapper({
val: val,
context: context
});
} else {
var ks = Object.keys(val),
$cond;
k = ks.length;
while (k--) {
$cond = ks[k];
nested = val[$cond];
if ($cond === '$not') {
if (nested && schematype && !schematype.caster) {
_keys = Object.keys(nested);
if (_keys.length && _keys[0].charAt(0) === '$') {
for (var key in nested) {
nested[key] = schematype.castForQueryWrapper({
$conditional: key,
val: nested[key],
context: context
});
}
} else {
val[$cond] = schematype.castForQueryWrapper({
$conditional: $cond,
val: nested,
context: context
});
}
continue;
}
cast(schematype.caster ? schematype.caster.schema : schema, nested, options, context);
} else {
val[$cond] = schematype.castForQueryWrapper({
$conditional: $cond,
val: nested,
context: context
});
}
}
}
} else if (Array.isArray(val) && ['Buffer', 'Array'].indexOf(schematype.instance) === -1) {
var casted = [];
for (var valIndex = 0; valIndex < val.length; valIndex++) {
casted.push(schematype.castForQueryWrapper({
val: val[valIndex],
context: context
}));
}
obj[path] = { $in: casted };
} else {
obj[path] = schematype.castForQueryWrapper({
val: val,
context: context
});
}
}
}
return obj;
};
function _cast(val, numbertype, context) {
if (Array.isArray(val)) {
val.forEach(function(item, i) {
if (Array.isArray(item) || utils.isObject(item)) {
return _cast(item, numbertype, context);
}
val[i] = numbertype.castForQueryWrapper({ val: item, context: context });
});
} else {
var nearKeys = Object.keys(val);
var nearLen = nearKeys.length;
while (nearLen--) {
var nkey = nearKeys[nearLen];
var item = val[nkey];
if (Array.isArray(item) || utils.isObject(item)) {
_cast(item, numbertype, context);
val[nkey] = item;
} else {
val[nkey] = numbertype.castForQuery({ val: item, context: context });
}
}
}
}
+221
View File
@@ -0,0 +1,221 @@
/*!
* Module dependencies.
*/
var EventEmitter = require('events').EventEmitter;
var STATES = require('./connectionstate');
/**
* Abstract Collection constructor
*
* This is the base class that drivers inherit from and implement.
*
* @param {String} name name of the collection
* @param {Connection} conn A MongooseConnection instance
* @param {Object} opts optional collection options
* @api public
*/
function Collection(name, conn, opts) {
if (opts === void 0) {
opts = {};
}
if (opts.capped === void 0) {
opts.capped = {};
}
opts.bufferCommands = undefined === opts.bufferCommands
? true
: opts.bufferCommands;
if (typeof opts.capped === 'number') {
opts.capped = {size: opts.capped};
}
this.opts = opts;
this.name = name;
this.collectionName = name;
this.conn = conn;
this.queue = [];
this.buffer = this.opts.bufferCommands;
this.emitter = new EventEmitter();
if (STATES.connected === this.conn.readyState) {
this.onOpen();
}
}
/**
* The collection name
*
* @api public
* @property name
*/
Collection.prototype.name;
/**
* The collection name
*
* @api public
* @property collectionName
*/
Collection.prototype.collectionName;
/**
* The Connection instance
*
* @api public
* @property conn
*/
Collection.prototype.conn;
/**
* Called when the database connects
*
* @api private
*/
Collection.prototype.onOpen = function() {
this.buffer = false;
var _this = this;
setImmediate(function() {
_this.doQueue();
});
};
/**
* Called when the database disconnects
*
* @api private
*/
Collection.prototype.onClose = function(force) {
if (this.opts.bufferCommands && !force) {
this.buffer = true;
}
};
/**
* Queues a method for later execution when its
* database connection opens.
*
* @param {String} name name of the method to queue
* @param {Array} args arguments to pass to the method when executed
* @api private
*/
Collection.prototype.addQueue = function(name, args) {
this.queue.push([name, args]);
return this;
};
/**
* Executes all queued methods and clears the queue.
*
* @api private
*/
Collection.prototype.doQueue = function() {
for (var i = 0, l = this.queue.length; i < l; i++) {
if (typeof this.queue[i][0] === 'function') {
this.queue[i][0].apply(this, this.queue[i][1]);
} else {
this[this.queue[i][0]].apply(this, this.queue[i][1]);
}
}
this.queue = [];
var _this = this;
process.nextTick(function() {
_this.emitter.emit('queue');
});
return this;
};
/**
* Abstract method that drivers must implement.
*/
Collection.prototype.ensureIndex = function() {
throw new Error('Collection#ensureIndex unimplemented by driver');
};
/**
* Abstract method that drivers must implement.
*/
Collection.prototype.createIndex = function() {
throw new Error('Collection#ensureIndex unimplemented by driver');
};
/**
* Abstract method that drivers must implement.
*/
Collection.prototype.findAndModify = function() {
throw new Error('Collection#findAndModify unimplemented by driver');
};
/**
* Abstract method that drivers must implement.
*/
Collection.prototype.findOne = function() {
throw new Error('Collection#findOne unimplemented by driver');
};
/**
* Abstract method that drivers must implement.
*/
Collection.prototype.find = function() {
throw new Error('Collection#find unimplemented by driver');
};
/**
* Abstract method that drivers must implement.
*/
Collection.prototype.insert = function() {
throw new Error('Collection#insert unimplemented by driver');
};
/**
* Abstract method that drivers must implement.
*/
Collection.prototype.save = function() {
throw new Error('Collection#save unimplemented by driver');
};
/**
* Abstract method that drivers must implement.
*/
Collection.prototype.update = function() {
throw new Error('Collection#update unimplemented by driver');
};
/**
* Abstract method that drivers must implement.
*/
Collection.prototype.getIndexes = function() {
throw new Error('Collection#getIndexes unimplemented by driver');
};
/**
* Abstract method that drivers must implement.
*/
Collection.prototype.mapReduce = function() {
throw new Error('Collection#mapReduce unimplemented by driver');
};
/*!
* Module exports.
*/
module.exports = Collection;
File diff suppressed because it is too large Load Diff
+27
View File
@@ -0,0 +1,27 @@
/*!
* Connection states
*/
var STATES = module.exports = exports = Object.create(null);
var disconnected = 'disconnected';
var connected = 'connected';
var connecting = 'connecting';
var disconnecting = 'disconnecting';
var unauthorized = 'unauthorized';
var uninitialized = 'uninitialized';
STATES[0] = disconnected;
STATES[1] = connected;
STATES[2] = connecting;
STATES[3] = disconnecting;
STATES[4] = unauthorized;
STATES[99] = uninitialized;
STATES[disconnected] = 0;
STATES[connected] = 1;
STATES[connecting] = 2;
STATES[disconnecting] = 3;
STATES[unauthorized] = 4;
STATES[uninitialized] = 99;
+328
View File
@@ -0,0 +1,328 @@
/*!
* Module dependencies.
*/
var PromiseProvider = require('../promise_provider');
var Readable = require('stream').Readable;
var util = require('util');
/**
* An AggregationCursor is a concurrency primitive for processing aggregation
* results one document at a time. It is analogous to QueryCursor.
*
* An AggregationCursor fulfills the [Node.js streams3 API](https://strongloop.com/strongblog/whats-new-io-js-beta-streams3/),
* in addition to several other mechanisms for loading documents from MongoDB
* one at a time.
*
* Creating an AggregationCursor executes the model's pre aggregate hooks,
* but **not** the model's post aggregate hooks.
*
* Unless you're an advanced user, do **not** instantiate this class directly.
* Use [`Aggregate#cursor()`](/docs/api.html#aggregate_Aggregate-cursor) instead.
*
* @param {Aggregate} agg
* @param {Object} options
* @inherits Readable
* @event `cursor`: Emitted when the cursor is created
* @event `error`: Emitted when an error occurred
* @event `data`: Emitted when the stream is flowing and the next doc is ready
* @event `end`: Emitted when the stream is exhausted
* @api public
*/
function AggregationCursor(agg) {
Readable.call(this, { objectMode: true });
this.cursor = null;
this.agg = agg;
this._transforms = [];
var model = agg._model;
delete agg.options.cursor.useMongooseAggCursor;
_init(model, this, agg);
}
util.inherits(AggregationCursor, Readable);
/*!
* ignore
*/
function _init(model, c, agg) {
if (!model.collection.buffer) {
model.hooks.execPre('aggregate', agg, function() {
c.cursor = model.collection.aggregate(agg._pipeline, agg.options || {});
c.emit('cursor', c.cursor);
});
} else {
model.collection.emitter.once('queue', function() {
model.hooks.execPre('aggregate', agg, function() {
c.cursor = model.collection.aggregate(agg._pipeline, agg.options || {});
c.emit('cursor', c.cursor);
});
});
}
}
/*!
* Necessary to satisfy the Readable API
*/
AggregationCursor.prototype._read = function() {
var _this = this;
_next(this, function(error, doc) {
if (error) {
return _this.emit('error', error);
}
if (!doc) {
_this.push(null);
_this.cursor.close(function(error) {
if (error) {
return _this.emit('error', error);
}
setTimeout(function() {
_this.emit('close');
}, 0);
});
return;
}
_this.push(doc);
});
};
/**
* Registers a transform function which subsequently maps documents retrieved
* via the streams interface or `.next()`
*
* ####Example
*
* // Map documents returned by `data` events
* Thing.
* find({ name: /^hello/ }).
* cursor().
* map(function (doc) {
* doc.foo = "bar";
* return doc;
* })
* on('data', function(doc) { console.log(doc.foo); });
*
* // Or map documents returned by `.next()`
* var cursor = Thing.find({ name: /^hello/ }).
* cursor().
* map(function (doc) {
* doc.foo = "bar";
* return doc;
* });
* cursor.next(function(error, doc) {
* console.log(doc.foo);
* });
*
* @param {Function} fn
* @return {QueryCursor}
* @api public
* @method map
*/
AggregationCursor.prototype.map = function(fn) {
this._transforms.push(fn);
return this;
};
/*!
* Marks this cursor as errored
*/
AggregationCursor.prototype._markError = function(error) {
this._error = error;
return this;
};
/**
* Marks this cursor as closed. Will stop streaming and subsequent calls to
* `next()` will error.
*
* @param {Function} callback
* @return {Promise}
* @api public
* @method close
* @emits close
* @see MongoDB driver cursor#close http://mongodb.github.io/node-mongodb-native/2.1/api/Cursor.html#close
*/
AggregationCursor.prototype.close = function(callback) {
var Promise = PromiseProvider.get();
var _this = this;
return new Promise.ES6(function(resolve, reject) {
_this.cursor.close(function(error) {
if (error) {
callback && callback(error);
reject(error);
return _this.listeners('error').length > 0 &&
_this.emit('error', error);
}
_this.emit('close');
resolve();
callback && callback();
});
});
};
/**
* Get the next document from this cursor. Will return `null` when there are
* no documents left.
*
* @param {Function} callback
* @return {Promise}
* @api public
* @method next
*/
AggregationCursor.prototype.next = function(callback) {
var Promise = PromiseProvider.get();
var _this = this;
return new Promise.ES6(function(resolve, reject) {
_next(_this, function(error, doc) {
if (error) {
callback && callback(error);
return reject(error);
}
callback && callback(null, doc);
resolve(doc);
});
});
};
/**
* Execute `fn` for every document in the cursor. If `fn` returns a promise,
* will wait for the promise to resolve before iterating on to the next one.
* Returns a promise that resolves when done.
*
* @param {Function} fn
* @param {Function} [callback] executed when all docs have been processed
* @return {Promise}
* @api public
* @method eachAsync
*/
AggregationCursor.prototype.eachAsync = function(fn, callback) {
var Promise = PromiseProvider.get();
var _this = this;
var handleNextResult = function(doc, callback) {
var promise = fn(doc);
if (promise && typeof promise.then === 'function') {
promise.then(
function() { callback(null); },
function(error) { callback(error); });
} else {
callback(null);
}
};
var iterate = function(callback) {
return _next(_this, function(error, doc) {
if (error) {
return callback(error);
}
if (!doc) {
return callback(null);
}
handleNextResult(doc, function(error) {
if (error) {
return callback(error);
}
// Make sure to clear the stack re: gh-4697
setTimeout(function() {
iterate(callback);
}, 0);
});
});
};
return new Promise.ES6(function(resolve, reject) {
iterate(function(error) {
if (error) {
callback && callback(error);
return reject(error);
}
callback && callback(null);
return resolve();
});
});
};
/**
* Adds a [cursor flag](http://mongodb.github.io/node-mongodb-native/2.2/api/Cursor.html#addCursorFlag).
* Useful for setting the `noCursorTimeout` and `tailable` flags.
*
* @param {String} flag
* @param {Boolean} value
* @return {AggregationCursor} this
* @api public
* @method addCursorFlag
*/
AggregationCursor.prototype.addCursorFlag = function(flag, value) {
var _this = this;
_waitForCursor(this, function() {
_this.cursor.addCursorFlag(flag, value);
});
return this;
};
/*!
* ignore
*/
function _waitForCursor(ctx, cb) {
if (ctx.cursor) {
return cb();
}
ctx.once('cursor', function() {
cb();
});
}
/*!
* Get the next doc from the underlying cursor and mongooseify it
* (populate, etc.)
*/
function _next(ctx, cb) {
var callback = cb;
if (ctx._transforms.length) {
callback = function(err, doc) {
if (err || doc === null) {
return cb(err, doc);
}
cb(err, ctx._transforms.reduce(function(doc, fn) {
return fn(doc);
}, doc));
};
}
if (ctx._error) {
return process.nextTick(function() {
callback(ctx._error);
});
}
if (ctx.cursor) {
return ctx.cursor.next(function(error, doc) {
if (error) {
return callback(error);
}
if (!doc) {
return callback(null, null);
}
callback(null, doc);
});
} else {
ctx.once('cursor', function() {
_next(ctx, cb);
});
}
}
module.exports = AggregationCursor;
+320
View File
@@ -0,0 +1,320 @@
/*!
* Module dependencies.
*/
var PromiseProvider = require('../promise_provider');
var Readable = require('stream').Readable;
var eachAsync = require('../services/cursor/eachAsync');
var helpers = require('../queryhelpers');
var util = require('util');
/**
* A QueryCursor is a concurrency primitive for processing query results
* one document at a time. A QueryCursor fulfills the [Node.js streams3 API](https://strongloop.com/strongblog/whats-new-io-js-beta-streams3/),
* in addition to several other mechanisms for loading documents from MongoDB
* one at a time.
*
* QueryCursors execute the model's pre find hooks, but **not** the model's
* post find hooks.
*
* Unless you're an advanced user, do **not** instantiate this class directly.
* Use [`Query#cursor()`](/docs/api.html#query_Query-cursor) instead.
*
* @param {Query} query
* @param {Object} options query options passed to `.find()`
* @inherits Readable
* @event `cursor`: Emitted when the cursor is created
* @event `error`: Emitted when an error occurred
* @event `data`: Emitted when the stream is flowing and the next doc is ready
* @event `end`: Emitted when the stream is exhausted
* @api public
*/
function QueryCursor(query, options) {
Readable.call(this, { objectMode: true });
this.cursor = null;
this.query = query;
this._transforms = options.transform ? [options.transform] : [];
var _this = this;
var model = query.model;
model.hooks.execPre('find', query, function() {
model.collection.find(query._conditions, options, function(err, cursor) {
if (_this._error) {
cursor.close(function() {});
_this.listeners('error').length > 0 && _this.emit('error', _this._error);
}
if (err) {
return _this.emit('error', err);
}
_this.cursor = cursor;
_this.emit('cursor', cursor);
});
});
}
util.inherits(QueryCursor, Readable);
/*!
* Necessary to satisfy the Readable API
*/
QueryCursor.prototype._read = function() {
var _this = this;
_next(this, function(error, doc) {
if (error) {
return _this.emit('error', error);
}
if (!doc) {
_this.push(null);
_this.cursor.close(function(error) {
if (error) {
return _this.emit('error', error);
}
setTimeout(function() {
_this.emit('close');
}, 0);
});
return;
}
_this.push(doc);
});
};
/**
* Registers a transform function which subsequently maps documents retrieved
* via the streams interface or `.next()`
*
* ####Example
*
* // Map documents returned by `data` events
* Thing.
* find({ name: /^hello/ }).
* cursor().
* map(function (doc) {
* doc.foo = "bar";
* return doc;
* })
* on('data', function(doc) { console.log(doc.foo); });
*
* // Or map documents returned by `.next()`
* var cursor = Thing.find({ name: /^hello/ }).
* cursor().
* map(function (doc) {
* doc.foo = "bar";
* return doc;
* });
* cursor.next(function(error, doc) {
* console.log(doc.foo);
* });
*
* @param {Function} fn
* @return {QueryCursor}
* @api public
* @method map
*/
QueryCursor.prototype.map = function(fn) {
this._transforms.push(fn);
return this;
};
/*!
* Marks this cursor as errored
*/
QueryCursor.prototype._markError = function(error) {
this._error = error;
return this;
};
/**
* Marks this cursor as closed. Will stop streaming and subsequent calls to
* `next()` will error.
*
* @param {Function} callback
* @return {Promise}
* @api public
* @method close
* @emits close
* @see MongoDB driver cursor#close http://mongodb.github.io/node-mongodb-native/2.1/api/Cursor.html#close
*/
QueryCursor.prototype.close = function(callback) {
var Promise = PromiseProvider.get();
var _this = this;
return new Promise.ES6(function(resolve, reject) {
_this.cursor.close(function(error) {
if (error) {
callback && callback(error);
reject(error);
return _this.listeners('error').length > 0 &&
_this.emit('error', error);
}
_this.emit('close');
resolve();
callback && callback();
});
});
};
/**
* Get the next document from this cursor. Will return `null` when there are
* no documents left.
*
* @param {Function} callback
* @return {Promise}
* @api public
* @method next
*/
QueryCursor.prototype.next = function(callback) {
var Promise = PromiseProvider.get();
var _this = this;
return new Promise.ES6(function(resolve, reject) {
_next(_this, function(error, doc) {
if (error) {
callback && callback(error);
return reject(error);
}
callback && callback(null, doc);
resolve(doc);
});
});
};
/**
* Execute `fn` for every document in the cursor. If `fn` returns a promise,
* will wait for the promise to resolve before iterating on to the next one.
* Returns a promise that resolves when done.
*
* @param {Function} fn
* @param {Object} [options]
* @param {Number} [options.parallel] the number of promises to execute in parallel. Defaults to 1.
* @param {Function} [callback] executed when all docs have been processed
* @return {Promise}
* @api public
* @method eachAsync
*/
QueryCursor.prototype.eachAsync = function(fn, opts, callback) {
var _this = this;
if (typeof opts === 'function') {
callback = opts;
opts = {};
}
opts = opts || {};
return eachAsync(function(cb) { return _next(_this, cb); }, fn, opts, callback);
};
/**
* Adds a [cursor flag](http://mongodb.github.io/node-mongodb-native/2.2/api/Cursor.html#addCursorFlag).
* Useful for setting the `noCursorTimeout` and `tailable` flags.
*
* @param {String} flag
* @param {Boolean} value
* @return {AggregationCursor} this
* @api public
* @method addCursorFlag
*/
QueryCursor.prototype.addCursorFlag = function(flag, value) {
var _this = this;
_waitForCursor(this, function() {
_this.cursor.addCursorFlag(flag, value);
});
return this;
};
/*!
* Get the next doc from the underlying cursor and mongooseify it
* (populate, etc.)
*/
function _next(ctx, cb) {
var callback = cb;
if (ctx._transforms.length) {
callback = function(err, doc) {
if (err || doc === null) {
return cb(err, doc);
}
cb(err, ctx._transforms.reduce(function(doc, fn) {
return fn(doc);
}, doc));
};
}
if (ctx._error) {
return process.nextTick(function() {
callback(ctx._error);
});
}
if (ctx.cursor) {
return ctx.cursor.next(function(error, doc) {
if (error) {
return callback(error);
}
if (!doc) {
return callback(null, null);
}
var opts = ctx.query._mongooseOptions;
if (!opts.populate) {
return opts.lean === true ?
callback(null, doc) :
_create(ctx, doc, null, callback);
}
var pop = helpers.preparePopulationOptionsMQ(ctx.query,
ctx.query._mongooseOptions);
pop.__noPromise = true;
ctx.query.model.populate(doc, pop, function(err, doc) {
if (err) {
return callback(err);
}
return opts.lean === true ?
callback(null, doc) :
_create(ctx, doc, pop, callback);
});
});
} else {
ctx.once('cursor', function() {
_next(ctx, cb);
});
}
}
/*!
* ignore
*/
function _waitForCursor(ctx, cb) {
if (ctx.cursor) {
return cb();
}
ctx.once('cursor', function() {
cb();
});
}
/*!
* Convert a raw doc into a full mongoose doc.
*/
function _create(ctx, doc, populatedIds, cb) {
var instance = helpers.createModel(ctx.query.model, doc, ctx.query._fields);
var opts = populatedIds ?
{ populated: populatedIds } :
undefined;
instance.init(doc, opts, function(err) {
if (err) {
return cb(err);
}
cb(null, instance);
});
}
module.exports = QueryCursor;
File diff suppressed because it is too large Load Diff
+30
View File
@@ -0,0 +1,30 @@
'use strict';
/* eslint-env browser */
/*!
* Module dependencies.
*/
var Document = require('./document.js');
var BrowserDocument = require('./browserDocument.js');
var isBrowser = false;
/**
* Returns the Document constructor for the current context
*
* @api private
*/
module.exports = function() {
if (isBrowser) {
return BrowserDocument;
}
return Document;
};
/*!
* ignore
*/
module.exports.setBrowser = function(flag) {
isBrowser = flag;
};
+17
View File
@@ -0,0 +1,17 @@
'use strict';
/* eslint-env browser */
/*!
* Module dependencies.
*/
var BrowserDocument = require('./browserDocument.js');
/**
* Returns the Document constructor for the current context
*
* @api private
*/
module.exports = function() {
return BrowserDocument;
};
+4
View File
@@ -0,0 +1,4 @@
# Driver Spec
TODO
@@ -0,0 +1,5 @@
/*!
* ignore
*/
module.exports = function() {};
+12
View File
@@ -0,0 +1,12 @@
/*!
* Module dependencies.
*/
var Binary = require('bson').Binary;
/*!
* Module exports.
*/
module.exports = exports = Binary;
@@ -0,0 +1,5 @@
/*!
* ignore
*/
module.exports = require('bson').Decimal128;
+8
View File
@@ -0,0 +1,8 @@
/*!
* Module exports.
*/
exports.Binary = require('./binary');
exports.Decimal128 = require('./decimal128');
exports.ObjectId = require('./objectid');
exports.ReadPreference = require('./ReadPreference');
+14
View File
@@ -0,0 +1,14 @@
/*!
* [node-mongodb-native](https://github.com/mongodb/node-mongodb-native) ObjectId
* @constructor NodeMongoDbObjectId
* @see ObjectId
*/
var ObjectId = require('bson').ObjectID;
/*!
* ignore
*/
module.exports = exports = ObjectId;
+20
View File
@@ -0,0 +1,20 @@
/*!
* ignore
*/
var driver;
if (typeof window === 'undefined') {
driver = require('./node-mongodb-native');
if (global.MONGOOSE_DRIVER_PATH) {
driver = require(global.MONGOOSE_DRIVER_PATH);
}
} else {
driver = require('./browser');
}
/*!
* ignore
*/
module.exports = driver;
+5
View File
@@ -0,0 +1,5 @@
/*!
* ignore
*/
module.exports = require('./browser');
@@ -0,0 +1,45 @@
/*!
* Module dependencies.
*/
var mongodb = require('mongodb');
var ReadPref = mongodb.ReadPreference;
/*!
* Converts arguments to ReadPrefs the driver
* can understand.
*
* @param {String|Array} pref
* @param {Array} [tags]
*/
module.exports = function readPref(pref, tags) {
if (Array.isArray(pref)) {
tags = pref[1];
pref = pref[0];
}
if (pref instanceof ReadPref) {
return pref;
}
switch (pref) {
case 'p':
pref = 'primary';
break;
case 'pp':
pref = 'primaryPreferred';
break;
case 's':
pref = 'secondary';
break;
case 'sp':
pref = 'secondaryPreferred';
break;
case 'n':
pref = 'nearest';
break;
}
return new ReadPref(pref, tags);
};
@@ -0,0 +1,8 @@
/*!
* Module dependencies.
*/
var Binary = require('mongodb').Binary;
module.exports = exports = Binary;
@@ -0,0 +1,271 @@
/*!
* Module dependencies.
*/
var MongooseCollection = require('../../collection');
var Collection = require('mongodb').Collection;
var utils = require('../../utils');
/**
* A [node-mongodb-native](https://github.com/mongodb/node-mongodb-native) collection implementation.
*
* All methods methods from the [node-mongodb-native](https://github.com/mongodb/node-mongodb-native) driver are copied and wrapped in queue management.
*
* @inherits Collection
* @api private
*/
function NativeCollection() {
this.collection = null;
MongooseCollection.apply(this, arguments);
}
/*!
* Inherit from abstract Collection.
*/
NativeCollection.prototype.__proto__ = MongooseCollection.prototype;
/**
* Called when the connection opens.
*
* @api private
*/
NativeCollection.prototype.onOpen = function() {
var _this = this;
// always get a new collection in case the user changed host:port
// of parent db instance when re-opening the connection.
if (!_this.opts.capped.size) {
// non-capped
callback(null, _this.conn.db.collection(_this.name));
return _this.collection;
}
// capped
return _this.conn.db.collection(_this.name, function(err, c) {
if (err) return callback(err);
// discover if this collection exists and if it is capped
_this.conn.db.listCollections({name: _this.name}).toArray(function(err, docs) {
if (err) {
return callback(err);
}
var doc = docs[0];
var exists = !!doc;
if (exists) {
if (doc.options && doc.options.capped) {
callback(null, c);
} else {
var msg = 'A non-capped collection exists with the name: ' + _this.name + '\n\n'
+ ' To use this collection as a capped collection, please '
+ 'first convert it.\n'
+ ' http://www.mongodb.org/display/DOCS/Capped+Collections#CappedCollections-Convertingacollectiontocapped';
err = new Error(msg);
callback(err);
}
} else {
// create
var opts = utils.clone(_this.opts.capped);
opts.capped = true;
_this.conn.db.createCollection(_this.name, opts, callback);
}
});
});
function callback(err, collection) {
if (err) {
// likely a strict mode error
_this.conn.emit('error', err);
} else {
_this.collection = collection;
MongooseCollection.prototype.onOpen.call(_this);
}
}
};
/**
* Called when the connection closes
*
* @api private
*/
NativeCollection.prototype.onClose = function(force) {
MongooseCollection.prototype.onClose.call(this, force);
};
/*!
* Copy the collection methods and make them subject to queues
*/
function iter(i) {
NativeCollection.prototype[i] = function() {
// If user force closed, queueing will hang forever. See #5664
if (this.opts.$wasForceClosed) {
return this.conn.db.collection(this.name)[i].apply(collection, args);
}
if (this.buffer) {
this.addQueue(i, arguments);
return;
}
var collection = this.collection;
var args = arguments;
var _this = this;
var debug = _this.conn.base.options.debug;
if (debug) {
if (typeof debug === 'function') {
debug.apply(_this,
[_this.name, i].concat(utils.args(args, 0, args.length - 1)));
} else {
this.$print(_this.name, i, args);
}
}
try {
return collection[i].apply(collection, args);
} catch (error) {
// Collection operation may throw because of max bson size, catch it here
// See gh-3906
if (args.length > 0 &&
typeof args[args.length - 1] === 'function') {
args[args.length - 1](error);
} else {
throw error;
}
}
};
}
for (var i in Collection.prototype) {
// Janky hack to work around gh-3005 until we can get rid of the mongoose
// collection abstraction
try {
if (typeof Collection.prototype[i] !== 'function') {
continue;
}
} catch (e) {
continue;
}
iter(i);
}
/**
* Debug print helper
*
* @api public
* @method $print
*/
NativeCollection.prototype.$print = function(name, i, args) {
var moduleName = '\x1B[0;36mMongoose:\x1B[0m ';
var functionCall = [name, i].join('.');
var _args = [];
for (var j = args.length - 1; j >= 0; --j) {
if (this.$format(args[j]) || _args.length) {
_args.unshift(this.$format(args[j]));
}
}
var params = '(' + _args.join(', ') + ')';
console.error(moduleName + functionCall + params);
};
/**
* Formatter for debug print args
*
* @api public
* @method $format
*/
NativeCollection.prototype.$format = function(arg) {
var type = typeof arg;
if (type === 'function' || type === 'undefined') return '';
return format(arg);
};
/*!
* Debug print helper
*/
function map(o) {
return format(o, true);
}
function formatObjectId(x, key) {
var representation = 'ObjectId("' + x[key].toHexString() + '")';
x[key] = {inspect: function() { return representation; }};
}
function formatDate(x, key) {
var representation = 'new Date("' + x[key].toUTCString() + '")';
x[key] = {inspect: function() { return representation; }};
}
function format(obj, sub) {
if (obj && typeof obj.toBSON === 'function') {
obj = obj.toBSON();
}
var x = utils.clone(obj, {retainKeyOrder: 1, transform: false});
var representation;
if (x != null) {
if (x.constructor.name === 'Binary') {
x = 'BinData(' + x.sub_type + ', "' + x.toString('base64') + '")';
} else if (x.constructor.name === 'ObjectID') {
representation = 'ObjectId("' + x.toHexString() + '")';
x = {inspect: function() { return representation; }};
} else if (x.constructor.name === 'Date') {
representation = 'new Date("' + x.toUTCString() + '")';
x = {inspect: function() { return representation; }};
} else if (x.constructor.name === 'Object') {
var keys = Object.keys(x);
var numKeys = keys.length;
var key;
for (var i = 0; i < numKeys; ++i) {
key = keys[i];
if (x[key]) {
if (typeof x[key].toBSON === 'function') {
x[key] = x[key].toBSON();
}
if (x[key].constructor.name === 'Binary') {
x[key] = 'BinData(' + x[key].sub_type + ', "' +
x[key].buffer.toString('base64') + '")';
} else if (x[key].constructor.name === 'Object') {
x[key] = format(x[key], true);
} else if (x[key].constructor.name === 'ObjectID') {
formatObjectId(x, key);
} else if (x[key].constructor.name === 'Date') {
formatDate(x, key);
} else if (Array.isArray(x[key])) {
x[key] = x[key].map(map);
}
}
}
}
if (sub) return x;
}
return require('util')
.inspect(x, false, 10, true)
.replace(/\n/g, '')
.replace(/\s{2,}/g, ' ');
}
/**
* Retreives information about this collections indexes.
*
* @param {Function} callback
* @method getIndexes
* @api public
*/
NativeCollection.prototype.getIndexes = NativeCollection.prototype.indexInformation;
/*!
* Module exports.
*/
module.exports = NativeCollection;
@@ -0,0 +1,403 @@
/*!
* Module dependencies.
*/
var MongooseConnection = require('../../connection');
var mongo = require('mongodb');
var Db = mongo.Db;
var Server = mongo.Server;
var Mongos = mongo.Mongos;
var STATES = require('../../connectionstate');
var ReplSetServers = mongo.ReplSet;
var DisconnectedError = require('../../error/disconnected');
/**
* A [node-mongodb-native](https://github.com/mongodb/node-mongodb-native) connection implementation.
*
* @inherits Connection
* @api private
*/
function NativeConnection() {
MongooseConnection.apply(this, arguments);
this._listening = false;
}
/**
* Expose the possible connection states.
* @api public
*/
NativeConnection.STATES = STATES;
/*!
* Inherits from Connection.
*/
NativeConnection.prototype.__proto__ = MongooseConnection.prototype;
/**
* Opens the connection to MongoDB.
*
* @param {Function} fn
* @return {Connection} this
* @api private
*/
NativeConnection.prototype.doOpen = function(fn) {
var _this = this;
var server = new Server(this.host, this.port, this.options.server);
if (this.options && this.options.mongos) {
var mongos = new Mongos([server], this.options.mongos);
this.db = new Db(this.name, mongos, this.options.db);
} else {
this.db = new Db(this.name, server, this.options.db);
}
this.db.open(function(err) {
listen(_this);
if (!mongos) {
server.s.server.on('error', function(error) {
if (/after \d+ attempts/.test(error.message)) {
_this.emit('error', new DisconnectedError(server.s.server.name));
}
});
}
if (err) return fn(err);
fn();
});
return this;
};
/**
* Switches to a different database using the same connection pool.
*
* Returns a new connection object, with the new db.
*
* @param {String} name The database name
* @return {Connection} New Connection Object
* @api public
*/
NativeConnection.prototype.useDb = function(name) {
// we have to manually copy all of the attributes...
var newConn = new this.constructor();
newConn.name = name;
newConn.base = this.base;
newConn.collections = {};
newConn.models = {};
newConn.replica = this.replica;
newConn.hosts = this.hosts;
newConn.host = this.host;
newConn.port = this.port;
newConn.user = this.user;
newConn.pass = this.pass;
newConn.options = this.options;
newConn._readyState = this._readyState;
newConn._closeCalled = this._closeCalled;
newConn._hasOpened = this._hasOpened;
newConn._listening = false;
// First, when we create another db object, we are not guaranteed to have a
// db object to work with. So, in the case where we have a db object and it
// is connected, we can just proceed with setting everything up. However, if
// we do not have a db or the state is not connected, then we need to wait on
// the 'open' event of the connection before doing the rest of the setup
// the 'connected' event is the first time we'll have access to the db object
var _this = this;
if (this.db && this._readyState === STATES.connected) {
wireup();
} else {
this.once('connected', wireup);
}
function wireup() {
newConn.db = _this.db.db(name);
newConn.onOpen();
// setup the events appropriately
listen(newConn);
}
newConn.name = name;
// push onto the otherDbs stack, this is used when state changes
this.otherDbs.push(newConn);
newConn.otherDbs.push(this);
return newConn;
};
/*!
* Register listeners for important events and bubble appropriately.
*/
function listen(conn) {
if (conn.db._listening) {
return;
}
conn.db._listening = true;
conn.db.on('close', function(force) {
if (conn._closeCalled) return;
// the driver never emits an `open` event. auto_reconnect still
// emits a `close` event but since we never get another
// `open` we can't emit close
if (conn.db.serverConfig.autoReconnect) {
conn.readyState = STATES.disconnected;
conn.emit('close');
return;
}
conn.onClose(force);
});
conn.db.on('error', function(err) {
conn.emit('error', err);
});
conn.db.on('reconnect', function() {
conn.readyState = STATES.connected;
conn.emit('reconnect');
conn.emit('reconnected');
conn.onOpen();
});
conn.db.on('timeout', function(err) {
conn.emit('timeout', err);
});
conn.db.on('open', function(err, db) {
if (STATES.disconnected === conn.readyState && db && db.databaseName) {
conn.readyState = STATES.connected;
conn.emit('reconnect');
conn.emit('reconnected');
}
});
conn.db.on('parseError', function(err) {
conn.emit('parseError', err);
});
}
/**
* Opens a connection to a MongoDB ReplicaSet.
*
* See description of [doOpen](#NativeConnection-doOpen) for server options. In this case `options.replset` is also passed to ReplSetServers.
*
* @param {Function} fn
* @api private
* @return {Connection} this
*/
NativeConnection.prototype.doOpenSet = function(fn) {
var servers = [],
_this = this;
this.hosts.forEach(function(server) {
var host = server.host || server.ipc;
var port = server.port || 27017;
servers.push(new Server(host, port, _this.options.server));
});
var server = this.options.mongos
? new Mongos(servers, this.options.mongos)
: new ReplSetServers(servers, this.options.replset || this.options.replSet);
this.db = new Db(this.name, server, this.options.db);
this.db.s.topology.on('left', function(data) {
_this.emit('left', data);
});
this.db.s.topology.on('joined', function(data) {
_this.emit('joined', data);
});
this.db.on('fullsetup', function() {
_this.emit('fullsetup');
});
this.db.on('all', function() {
_this.emit('all');
});
this.db.open(function(err) {
if (err) return fn(err);
fn();
listen(_this);
});
return this;
};
/**
* Closes the connection
*
* @param {Boolean} [force]
* @param {Function} [fn]
* @return {Connection} this
* @api private
*/
NativeConnection.prototype.doClose = function(force, fn) {
this.db.close(force, fn);
return this;
};
/**
* Prepares default connection options for the node-mongodb-native driver.
*
* _NOTE: `passed` options take precedence over connection string options._
*
* @param {Object} passed options that were passed directly during connection
* @param {Object} [connStrOptions] options that were passed in the connection string
* @api private
*/
NativeConnection.prototype.parseOptions = function(passed, connStrOpts) {
var o = passed ? require('../../utils').clone(passed) : {};
o.db || (o.db = {});
o.auth || (o.auth = {});
o.server || (o.server = {});
o.replset || (o.replset = o.replSet) || (o.replset = {});
o.server.socketOptions || (o.server.socketOptions = {});
o.replset.socketOptions || (o.replset.socketOptions = {});
o.mongos || (o.mongos = (connStrOpts && connStrOpts.mongos));
(o.mongos === true) && (o.mongos = {});
var opts = connStrOpts || {};
Object.keys(opts).forEach(function(name) {
switch (name) {
case 'ssl':
o.server.ssl = opts.ssl;
o.replset.ssl = opts.ssl;
o.mongos && (o.mongos.ssl = opts.ssl);
break;
case 'poolSize':
if (typeof o.server[name] === 'undefined') {
o.server[name] = o.replset[name] = opts[name];
}
break;
case 'slaveOk':
if (typeof o.server.slave_ok === 'undefined') {
o.server.slave_ok = opts[name];
}
break;
case 'autoReconnect':
if (typeof o.server.auto_reconnect === 'undefined') {
o.server.auto_reconnect = opts[name];
}
break;
case 'socketTimeoutMS':
case 'connectTimeoutMS':
if (typeof o.server.socketOptions[name] === 'undefined') {
o.server.socketOptions[name] = o.replset.socketOptions[name] = opts[name];
}
break;
case 'authdb':
if (typeof o.auth.authdb === 'undefined') {
o.auth.authdb = opts[name];
}
break;
case 'authSource':
if (typeof o.auth.authSource === 'undefined') {
o.auth.authSource = opts[name];
}
break;
case 'authMechanism':
if (typeof o.auth.authMechanism === 'undefined') {
o.auth.authMechanism = opts[name];
}
break;
case 'retries':
case 'reconnectWait':
case 'rs_name':
if (typeof o.replset[name] === 'undefined') {
o.replset[name] = opts[name];
}
break;
case 'replicaSet':
if (typeof o.replset.rs_name === 'undefined') {
o.replset.rs_name = opts[name];
}
break;
case 'readSecondary':
if (typeof o.replset.read_secondary === 'undefined') {
o.replset.read_secondary = opts[name];
}
break;
case 'nativeParser':
if (typeof o.db.native_parser === 'undefined') {
o.db.native_parser = opts[name];
}
break;
case 'w':
case 'safe':
case 'fsync':
case 'journal':
case 'wtimeoutMS':
if (typeof o.db[name] === 'undefined') {
o.db[name] = opts[name];
}
break;
case 'readPreference':
if (typeof o.db.readPreference === 'undefined') {
o.db.readPreference = opts[name];
}
break;
case 'readPreferenceTags':
if (typeof o.db.read_preference_tags === 'undefined') {
o.db.read_preference_tags = opts[name];
}
break;
case 'sslValidate':
o.server.sslValidate = opts.sslValidate;
o.replset.sslValidate = opts.sslValidate;
o.mongos && (o.mongos.sslValidate = opts.sslValidate);
}
});
if (!('auto_reconnect' in o.server)) {
o.server.auto_reconnect = true;
}
// mongoose creates its own ObjectIds
o.db.forceServerObjectId = false;
// default safe using new nomenclature
if (!('journal' in o.db || 'j' in o.db ||
'fsync' in o.db || 'safe' in o.db || 'w' in o.db)) {
o.db.w = 1;
}
if (o.promiseLibrary) {
o.db.promiseLibrary = o.promiseLibrary;
}
validate(o);
return o;
};
/*!
* Validates the driver db options.
*
* @param {Object} o
*/
function validate(o) {
if (o.db.w === -1 || o.db.w === 0) {
if (o.db.journal || o.db.fsync || o.db.safe) {
throw new Error(
'Invalid writeConcern: '
+ 'w set to -1 or 0 cannot be combined with safe|fsync|journal');
}
}
}
/*!
* Module exports.
*/
module.exports = NativeConnection;
@@ -0,0 +1,5 @@
/*!
* ignore
*/
module.exports = require('mongodb').Decimal128;
@@ -0,0 +1,8 @@
/*!
* Module exports.
*/
exports.Binary = require('./binary');
exports.Decimal128 = require('./decimal128');
exports.ObjectId = require('./objectid');
exports.ReadPreference = require('./ReadPreference');
@@ -0,0 +1,14 @@
/*!
* [node-mongodb-native](https://github.com/mongodb/node-mongodb-native) ObjectId
* @constructor NodeMongoDbObjectId
* @see ObjectId
*/
var ObjectId = require('mongodb').ObjectId;
/*!
* ignore
*/
module.exports = exports = ObjectId;
+36
View File
@@ -0,0 +1,36 @@
/*!
* Module dependencies.
*/
var MongooseError = require('./');
/*!
* MissingSchema Error constructor.
*
* @inherits MongooseError
*/
function MissingSchemaError() {
var msg = 'Schema hasn\'t been registered for document.\n'
+ 'Use mongoose.Document(name, schema)';
MongooseError.call(this, msg);
this.name = 'MissingSchemaError';
if (Error.captureStackTrace) {
Error.captureStackTrace(this);
} else {
this.stack = new Error().stack;
}
}
/*!
* Inherits from MongooseError.
*/
MissingSchemaError.prototype = Object.create(MongooseError.prototype);
MissingSchemaError.prototype.constructor = MongooseError;
/*!
* exports
*/
module.exports = MissingSchemaError;
+60
View File
@@ -0,0 +1,60 @@
/*!
* Module dependencies.
*/
var MongooseError = require('./');
var util = require('util');
/**
* Casting Error constructor.
*
* @param {String} type
* @param {String} value
* @inherits MongooseError
* @api private
*/
function CastError(type, value, path, reason) {
var stringValue = util.inspect(value);
stringValue = stringValue.replace(/^'/, '"').replace(/'$/, '"');
if (stringValue.charAt(0) !== '"') {
stringValue = '"' + stringValue + '"';
}
MongooseError.call(this, 'Cast to ' + type + ' failed for value ' +
stringValue + ' at path "' + path + '"');
this.name = 'CastError';
if (Error.captureStackTrace) {
Error.captureStackTrace(this);
} else {
this.stack = new Error().stack;
}
this.stringValue = stringValue;
this.kind = type;
this.value = value;
this.path = path;
this.reason = reason;
}
/*!
* Inherits from MongooseError.
*/
CastError.prototype = Object.create(MongooseError.prototype);
CastError.prototype.constructor = MongooseError;
/*!
* ignore
*/
CastError.prototype.setModel = function(model) {
this.model = model;
this.message = 'Cast to ' + this.kind + ' failed for value ' +
this.stringValue + ' at path "' + this.path + '"' + ' for model "' +
model.modelName + '"';
};
/*!
* exports
*/
module.exports = CastError;
+40
View File
@@ -0,0 +1,40 @@
/*!
* Module dependencies.
*/
var MongooseError = require('./');
/**
* Casting Error constructor.
*
* @param {String} type
* @param {String} value
* @inherits MongooseError
* @api private
*/
function DisconnectedError(connectionString) {
MongooseError.call(this, 'Ran out of retries trying to reconnect to "' +
connectionString + '". Try setting `server.reconnectTries` and ' +
'`server.reconnectInterval` to something higher.');
this.name = 'DisconnectedError';
if (Error.captureStackTrace) {
Error.captureStackTrace(this);
} else {
this.stack = new Error().stack;
}
}
/*!
* Inherits from MongooseError.
*/
DisconnectedError.prototype = Object.create(MongooseError.prototype);
DisconnectedError.prototype.constructor = MongooseError;
/*!
* exports
*/
module.exports = DisconnectedError;
+46
View File
@@ -0,0 +1,46 @@
/*!
* Module dependencies.
*/
var MongooseError = require('./');
/*!
* DivergentArrayError constructor.
*
* @inherits MongooseError
*/
function DivergentArrayError(paths) {
var msg = 'For your own good, using `document.save()` to update an array '
+ 'which was selected using an $elemMatch projection OR '
+ 'populated using skip, limit, query conditions, or exclusion of '
+ 'the _id field when the operation results in a $pop or $set of '
+ 'the entire array is not supported. The following '
+ 'path(s) would have been modified unsafely:\n'
+ ' ' + paths.join('\n ') + '\n'
+ 'Use Model.update() to update these arrays instead.';
// TODO write up a docs page (FAQ) and link to it
MongooseError.call(this, msg);
this.name = 'DivergentArrayError';
if (Error.captureStackTrace) {
Error.captureStackTrace(this);
} else {
this.stack = new Error().stack;
}
}
/*!
* Inherits from MongooseError.
*/
DivergentArrayError.prototype = Object.create(MongooseError.prototype);
DivergentArrayError.prototype.constructor = MongooseError;
/*!
* exports
*/
module.exports = DivergentArrayError;
+66
View File
@@ -0,0 +1,66 @@
/**
* MongooseError constructor
*
* @param {String} msg Error message
* @inherits Error https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error
*/
function MongooseError(msg) {
Error.call(this);
if (Error.captureStackTrace) {
Error.captureStackTrace(this);
} else {
this.stack = new Error().stack;
}
this.message = msg;
this.name = 'MongooseError';
}
/*!
* Inherits from Error.
*/
MongooseError.prototype = Object.create(Error.prototype);
MongooseError.prototype.constructor = Error;
/*!
* Module exports.
*/
module.exports = exports = MongooseError;
/**
* The default built-in validator error messages.
*
* @see Error.messages #error_messages_MongooseError-messages
* @api public
*/
MongooseError.messages = require('./messages');
// backward compat
MongooseError.Messages = MongooseError.messages;
/**
* This error will be called when `save()` fails because the underlying
* document was not found. The constructor takes one parameter, the
* conditions that mongoose passed to `update()` when trying to update
* the document.
*
* @api public
*/
MongooseError.DocumentNotFoundError = require('./notFound');
/*!
* Expose subclasses
*/
MongooseError.CastError = require('./cast');
MongooseError.ValidationError = require('./validation');
MongooseError.ValidatorError = require('./validator');
MongooseError.VersionError = require('./version');
MongooseError.OverwriteModelError = require('./overwriteModel');
MongooseError.MissingSchemaError = require('./missingSchema');
MongooseError.DivergentArrayError = require('./divergentArray');
+44
View File
@@ -0,0 +1,44 @@
/**
* The default built-in validator error messages. These may be customized.
*
* // customize within each schema or globally like so
* var mongoose = require('mongoose');
* mongoose.Error.messages.String.enum = "Your custom message for {PATH}.";
*
* As you might have noticed, error messages support basic templating
*
* - `{PATH}` is replaced with the invalid document path
* - `{VALUE}` is replaced with the invalid value
* - `{TYPE}` is replaced with the validator type such as "regexp", "min", or "user defined"
* - `{MIN}` is replaced with the declared min value for the Number.min validator
* - `{MAX}` is replaced with the declared max value for the Number.max validator
*
* Click the "show code" link below to see all defaults.
*
* @static messages
* @receiver MongooseError
* @api public
*/
var msg = module.exports = exports = {};
msg.DocumentNotFoundError = null;
msg.general = {};
msg.general.default = 'Validator failed for path `{PATH}` with value `{VALUE}`';
msg.general.required = 'Path `{PATH}` is required.';
msg.Number = {};
msg.Number.min = 'Path `{PATH}` ({VALUE}) is less than minimum allowed value ({MIN}).';
msg.Number.max = 'Path `{PATH}` ({VALUE}) is more than maximum allowed value ({MAX}).';
msg.Date = {};
msg.Date.min = 'Path `{PATH}` ({VALUE}) is before minimum allowed value ({MIN}).';
msg.Date.max = 'Path `{PATH}` ({VALUE}) is after maximum allowed value ({MAX}).';
msg.String = {};
msg.String.enum = '`{VALUE}` is not a valid enum value for path `{PATH}`.';
msg.String.match = 'Path `{PATH}` is invalid ({VALUE}).';
msg.String.minlength = 'Path `{PATH}` (`{VALUE}`) is shorter than the minimum allowed length ({MINLENGTH}).';
msg.String.maxlength = 'Path `{PATH}` (`{VALUE}`) is longer than the maximum allowed length ({MAXLENGTH}).';
+37
View File
@@ -0,0 +1,37 @@
/*!
* Module dependencies.
*/
var MongooseError = require('./');
/*!
* MissingSchema Error constructor.
*
* @inherits MongooseError
*/
function MissingSchemaError(name) {
var msg = 'Schema hasn\'t been registered for model "' + name + '".\n'
+ 'Use mongoose.model(name, schema)';
MongooseError.call(this, msg);
this.name = 'MissingSchemaError';
if (Error.captureStackTrace) {
Error.captureStackTrace(this);
} else {
this.stack = new Error().stack;
}
}
/*!
* Inherits from MongooseError.
*/
MissingSchemaError.prototype = Object.create(MongooseError.prototype);
MissingSchemaError.prototype.constructor = MongooseError;
/*!
* exports
*/
module.exports = MissingSchemaError;
+50
View File
@@ -0,0 +1,50 @@
'use strict';
/*!
* Module dependencies.
*/
var MongooseError = require('./');
var util = require('util');
/*!
* OverwriteModel Error constructor.
*
* @inherits MongooseError
*/
function DocumentNotFoundError(query) {
var msg;
var messages = MongooseError.messages;
if (messages.DocumentNotFoundError != null) {
msg = typeof messages.DocumentNotFoundError === 'function' ?
messages.DocumentNotFoundError(query) :
messages.DocumentNotFoundError;
} else {
msg = 'No document found for query "' + util.inspect(query) + '"';
}
MongooseError.call(this, msg);
this.name = 'DocumentNotFoundError';
if (Error.captureStackTrace) {
Error.captureStackTrace(this);
} else {
this.stack = new Error().stack;
}
this.query = query;
}
/*!
* Inherits from MongooseError.
*/
DocumentNotFoundError.prototype = Object.create(MongooseError.prototype);
DocumentNotFoundError.prototype.constructor = MongooseError;
/*!
* exports
*/
module.exports = DocumentNotFoundError;
+35
View File
@@ -0,0 +1,35 @@
/*!
* Module dependencies.
*/
var MongooseError = require('./');
/**
* Strict mode error constructor
*
* @param {String} type
* @param {String} value
* @inherits MongooseError
* @api private
*/
function ObjectExpectedError(path, val) {
MongooseError.call(this, 'Tried to set nested object field `' + path +
'` to primitive value `' + val + '` and strict mode is set to throw.');
this.name = 'ObjectExpectedError';
if (Error.captureStackTrace) {
Error.captureStackTrace(this);
} else {
this.stack = new Error().stack;
}
this.path = path;
}
/*!
* Inherits from MongooseError.
*/
ObjectExpectedError.prototype = Object.create(MongooseError.prototype);
ObjectExpectedError.prototype.constructor = MongooseError;
module.exports = ObjectExpectedError;
+36
View File
@@ -0,0 +1,36 @@
/*!
* Module dependencies.
*/
var MongooseError = require('./');
/**
* Constructor for errors that happen when a parameter that's expected to be
* an object isn't an object
*
* @param {Any} value
* @param {String} paramName
* @param {String} fnName
* @inherits MongooseError
* @api private
*/
function ObjectParameterError(value, paramName, fnName) {
MongooseError.call(this, 'Parameter "' + paramName + '" to ' + fnName +
'() must be an object, got ' + value.toString());
this.name = 'ObjectParameterError';
if (Error.captureStackTrace) {
Error.captureStackTrace(this);
} else {
this.stack = new Error().stack;
}
}
/*!
* Inherits from MongooseError.
*/
ObjectParameterError.prototype = Object.create(MongooseError.prototype);
ObjectParameterError.prototype.constructor = MongooseError;
module.exports = ObjectParameterError;
+35
View File
@@ -0,0 +1,35 @@
/*!
* Module dependencies.
*/
var MongooseError = require('./');
/*!
* OverwriteModel Error constructor.
*
* @inherits MongooseError
*/
function OverwriteModelError(name) {
MongooseError.call(this, 'Cannot overwrite `' + name + '` model once compiled.');
this.name = 'OverwriteModelError';
if (Error.captureStackTrace) {
Error.captureStackTrace(this);
} else {
this.stack = new Error().stack;
}
}
/*!
* Inherits from MongooseError.
*/
OverwriteModelError.prototype = Object.create(MongooseError.prototype);
OverwriteModelError.prototype.constructor = MongooseError;
/*!
* exports
*/
module.exports = OverwriteModelError;
+36
View File
@@ -0,0 +1,36 @@
/*!
* Module dependencies.
*/
var MongooseError = require('./');
/**
* Strict mode error constructor
*
* @param {String} type
* @param {String} value
* @inherits MongooseError
* @api private
*/
function StrictModeError(path, msg) {
msg = msg || 'Field `' + path + '` is not in schema and strict ' +
'mode is set to throw.';
MongooseError.call(this, msg);
this.name = 'StrictModeError';
if (Error.captureStackTrace) {
Error.captureStackTrace(this);
} else {
this.stack = new Error().stack;
}
this.path = path;
}
/*!
* Inherits from MongooseError.
*/
StrictModeError.prototype = Object.create(MongooseError.prototype);
StrictModeError.prototype.constructor = MongooseError;
module.exports = StrictModeError;
+102
View File
@@ -0,0 +1,102 @@
/*!
* Module requirements
*/
var MongooseError = require('./');
var utils = require('../utils');
/**
* Document Validation Error
*
* @api private
* @param {Document} instance
* @inherits MongooseError
*/
function ValidationError(instance) {
this.errors = {};
this._message = '';
if (instance && instance.constructor.name === 'model') {
this._message = instance.constructor.modelName + ' validation failed';
MongooseError.call(this, this._message);
} else {
this._message = 'Validation failed';
MongooseError.call(this, this._message);
}
this.name = 'ValidationError';
if (Error.captureStackTrace) {
Error.captureStackTrace(this);
} else {
this.stack = new Error().stack;
}
if (instance) {
instance.errors = this.errors;
}
}
/*!
* Inherits from MongooseError.
*/
ValidationError.prototype = Object.create(MongooseError.prototype);
ValidationError.prototype.constructor = MongooseError;
/**
* Console.log helper
*/
ValidationError.prototype.toString = function() {
return this.name + ': ' + _generateMessage(this);
};
/*!
* inspect helper
*/
ValidationError.prototype.inspect = function() {
return utils.assign(new Error(this.message), this);
};
/*!
* Helper for JSON.stringify
*/
ValidationError.prototype.toJSON = function() {
return utils.assign({}, this, { message: this.message });
};
/*!
* add message
*/
ValidationError.prototype.addError = function(path, error) {
this.errors[path] = error;
this.message = this._message + ': ' + _generateMessage(this);
};
/*!
* ignore
*/
function _generateMessage(err) {
var keys = Object.keys(err.errors || {});
var len = keys.length;
var msgs = [];
var key;
for (var i = 0; i < len; ++i) {
key = keys[i];
if (err === err.errors[key]) {
continue;
}
msgs.push(key + ': ' + err.errors[key].message);
}
return msgs.join(', ');
}
/*!
* Module exports
*/
module.exports = exports = ValidationError;
+82
View File
@@ -0,0 +1,82 @@
/*!
* Module dependencies.
*/
var MongooseError = require('./');
/**
* Schema validator error
*
* @param {Object} properties
* @inherits MongooseError
* @api private
*/
function ValidatorError(properties) {
var msg = properties.message;
if (!msg) {
msg = MongooseError.messages.general.default;
}
var message = this.formatMessage(msg, properties);
MongooseError.call(this, message);
this.name = 'ValidatorError';
if (Error.captureStackTrace) {
Error.captureStackTrace(this);
} else {
this.stack = new Error().stack;
}
this.properties = properties;
this.kind = properties.type;
this.path = properties.path;
this.value = properties.value;
this.reason = properties.reason;
}
/*!
* Inherits from MongooseError
*/
ValidatorError.prototype = Object.create(MongooseError.prototype);
ValidatorError.prototype.constructor = MongooseError;
/*!
* The object used to define this validator. Not enumerable to hide
* it from `require('util').inspect()` output re: gh-3925
*/
Object.defineProperty(ValidatorError.prototype, 'properties', {
enumerable: false,
writable: true,
value: null
});
/*!
* Formats error messages
*/
ValidatorError.prototype.formatMessage = function(msg, properties) {
var propertyNames = Object.keys(properties);
for (var i = 0; i < propertyNames.length; ++i) {
var propertyName = propertyNames[i];
if (propertyName === 'message') {
continue;
}
msg = msg.replace('{' + propertyName.toUpperCase() + '}', properties[propertyName]);
}
return msg;
};
/*!
* toString helper
*/
ValidatorError.prototype.toString = function() {
return this.message;
};
/*!
* exports
*/
module.exports = ValidatorError;
+36
View File
@@ -0,0 +1,36 @@
'use strict';
/*!
* Module dependencies.
*/
var MongooseError = require('./');
/**
* Version Error constructor.
*
* @inherits MongooseError
* @api private
*/
function VersionError(doc, currentVersion, modifiedPaths) {
var modifiedPathsStr = modifiedPaths.join(', ');
MongooseError.call(this, 'No matching document found for id "' + doc._id +
'" version ' + currentVersion + ' modifiedPaths "' + modifiedPathsStr + '"');
this.name = 'VersionError';
this.version = currentVersion;
this.modifiedPaths = modifiedPaths;
}
/*!
* Inherits from MongooseError.
*/
VersionError.prototype = Object.create(MongooseError.prototype);
VersionError.prototype.constructor = MongooseError;
/*!
* exports
*/
module.exports = VersionError;
+863
View File
@@ -0,0 +1,863 @@
'use strict';
/*!
* Module dependencies.
*/
var Schema = require('./schema');
var SchemaType = require('./schematype');
var VirtualType = require('./virtualtype');
var STATES = require('./connectionstate');
var Types = require('./types');
var Query = require('./query');
var Model = require('./model');
var Document = require('./document');
var utils = require('./utils');
var format = utils.toCollectionName;
var pkg = require('../package.json');
var querystring = require('querystring');
var saveSubdocs = require('./plugins/saveSubdocs');
var validateBeforeSave = require('./plugins/validateBeforeSave');
var Aggregate = require('./aggregate');
var PromiseProvider = require('./promise_provider');
var shardingPlugin = require('./plugins/sharding');
/**
* Mongoose constructor.
*
* The exports object of the `mongoose` module is an instance of this class.
* Most apps will only use this one instance.
*
* @api public
*/
function Mongoose() {
this.connections = [];
this.models = {};
this.modelSchemas = {};
// default global options
this.options = {
pluralization: true
};
var conn = this.createConnection(); // default connection
conn.models = this.models;
Object.defineProperty(this, 'plugins', {
configurable: false,
enumerable: true,
writable: false,
value: [
[saveSubdocs, { deduplicate: true }],
[validateBeforeSave, { deduplicate: true }],
[shardingPlugin, { deduplicate: true }]
]
});
}
/**
* Expose connection states for user-land
*
*/
Mongoose.prototype.STATES = STATES;
/**
* Sets mongoose options
*
* ####Example:
*
* mongoose.set('test', value) // sets the 'test' option to `value`
*
* mongoose.set('debug', true) // enable logging collection methods + arguments to the console
*
* mongoose.set('debug', function(collectionName, methodName, arg1, arg2...) {}); // use custom function to log collection methods + arguments
*
* @param {String} key
* @param {String|Function|Boolean} value
* @api public
*/
Mongoose.prototype.set = function(key, value) {
if (arguments.length === 1) {
return this.options[key];
}
this.options[key] = value;
return this;
};
Mongoose.prototype.set.$hasSideEffects = true;
/**
* Gets mongoose options
*
* ####Example:
*
* mongoose.get('test') // returns the 'test' value
*
* @param {String} key
* @method get
* @api public
*/
Mongoose.prototype.get = Mongoose.prototype.set;
/*!
* ReplSet connection string check.
*/
var rgxReplSet = /^.+,.+$/;
/**
* Checks if ?replicaSet query parameter is specified in URI
*
* ####Example:
*
* checkReplicaSetInUri('localhost:27000?replicaSet=rs0'); // true
*
* @param {String} uri
* @return {boolean}
* @api private
*/
var checkReplicaSetInUri = function(uri) {
if (!uri) {
return false;
}
var queryStringStart = uri.indexOf('?');
var isReplicaSet = false;
if (queryStringStart !== -1) {
try {
var obj = querystring.parse(uri.substr(queryStringStart + 1));
if (obj && obj.replicaSet) {
isReplicaSet = true;
}
} catch (e) {
return false;
}
}
return isReplicaSet;
};
/**
* Creates a Connection instance.
*
* Each `connection` instance maps to a single database. This method is helpful when mangaging multiple db connections.
*
* If arguments are passed, they are proxied to either [Connection#open](#connection_Connection-open) or [Connection#openSet](#connection_Connection-openSet) appropriately. This means we can pass `db`, `server`, and `replset` options to the driver. _Note that the `safe` option specified in your schema will overwrite the `safe` db option specified here unless you set your schemas `safe` option to `undefined`. See [this](/docs/guide.html#safe) for more information._
*
* _Options passed take precedence over options included in connection strings._
*
* ####Example:
*
* // with mongodb:// URI
* db = mongoose.createConnection('mongodb://user:pass@localhost:port/database');
*
* // and options
* var opts = { db: { native_parser: true }}
* db = mongoose.createConnection('mongodb://user:pass@localhost:port/database', opts);
*
* // replica sets
* db = mongoose.createConnection('mongodb://user:pass@localhost:port,anotherhost:port,yetanother:port/database');
*
* // and options
* var opts = { replset: { strategy: 'ping', rs_name: 'testSet' }}
* db = mongoose.createConnection('mongodb://user:pass@localhost:port,anotherhost:port,yetanother:port/database', opts);
*
* // with [host, database_name[, port] signature
* db = mongoose.createConnection('localhost', 'database', port)
*
* // and options
* var opts = { server: { auto_reconnect: false }, user: 'username', pass: 'mypassword' }
* db = mongoose.createConnection('localhost', 'database', port, opts)
*
* // initialize now, connect later
* db = mongoose.createConnection();
* db.open('localhost', 'database', port, [opts]);
*
* @param {String} [uri] a mongodb:// URI
* @param {Object} [options] options to pass to the driver
* @param {Object} [options.config] mongoose-specific options
* @param {Boolean} [options.config.autoIndex] set to false to disable automatic index creation for all models associated with this connection.
* @param {Boolean} [options.useMongoClient] false by default, set to true to use new mongoose connection logic
* @see Connection#open #connection_Connection-open
* @see Connection#openSet #connection_Connection-openSet
* @return {Connection|Promise} the created Connection object, or promise that resolves to the connection if `useMongoClient` option specified.
* @api public
*/
Mongoose.prototype.createConnection = function(uri, options, callback) {
var conn = new Connection(this);
this.connections.push(conn);
var rsOption = options && (options.replset || options.replSet);
if (options && options.useMongoClient) {
return conn.openUri(uri, options, callback);
}
if (arguments.length) {
if (rgxReplSet.test(arguments[0]) || checkReplicaSetInUri(arguments[0])) {
conn._openSetWithoutPromise.apply(conn, arguments);
} else if (rsOption &&
(rsOption.replicaSet || rsOption.rs_name)) {
conn._openSetWithoutPromise.apply(conn, arguments);
} else {
conn._openWithoutPromise.apply(conn, arguments);
}
}
return conn;
};
Mongoose.prototype.createConnection.$hasSideEffects = true;
/**
* Opens the default mongoose connection.
*
* If arguments are passed, they are proxied to either
* [Connection#open](#connection_Connection-open) or
* [Connection#openSet](#connection_Connection-openSet) appropriately.
*
* _Options passed take precedence over options included in connection strings._
*
* ####Example:
*
* mongoose.connect('mongodb://user:pass@localhost:port/database');
*
* // replica sets
* var uri = 'mongodb://user:pass@localhost:port,anotherhost:port,yetanother:port/mydatabase';
* mongoose.connect(uri);
*
* // with options
* mongoose.connect(uri, options);
*
* // connecting to multiple mongos
* var uri = 'mongodb://hostA:27501,hostB:27501';
* var opts = { mongos: true };
* mongoose.connect(uri, opts);
*
* // optional callback that gets fired when initial connection completed
* var uri = 'mongodb://nonexistent.domain:27000';
* mongoose.connect(uri, function(error) {
* // if error is truthy, the initial connection failed.
* })
*
* @param {String} uri(s)
* @param {Object} [options]
* @param {Boolean} [options.useMongoClient] false by default, set to true to use new mongoose connection logic
* @param {Function} [callback]
* @see Mongoose#createConnection #index_Mongoose-createConnection
* @api public
* @return {MongooseThenable} pseudo-promise wrapper around this
*/
Mongoose.prototype.connect = function() {
var conn = this.connection;
if ((arguments.length === 2 || arguments.length === 3) &&
typeof arguments[0] === 'string' &&
typeof arguments[1] === 'object' &&
arguments[1].useMongoClient === true) {
return conn.openUri(arguments[0], arguments[1], arguments[2]);
}
if (rgxReplSet.test(arguments[0]) || checkReplicaSetInUri(arguments[0])) {
return new MongooseThenable(this, conn.openSet.apply(conn, arguments));
}
return new MongooseThenable(this, conn.open.apply(conn, arguments));
};
Mongoose.prototype.connect.$hasSideEffects = true;
/**
* Disconnects all connections.
*
* @param {Function} [fn] called after all connection close.
* @return {MongooseThenable} pseudo-promise wrapper around this
* @api public
*/
Mongoose.prototype.disconnect = function(fn) {
var _this = this;
var Promise = PromiseProvider.get();
return new MongooseThenable(this, new Promise.ES6(function(resolve, reject) {
var remaining = _this.connections.length;
if (remaining <= 0) {
fn && fn();
resolve();
return;
}
_this.connections.forEach(function(conn) {
conn.close(function(error) {
if (error) {
fn && fn(error);
reject(error);
return;
}
if (!--remaining) {
fn && fn();
resolve();
}
});
});
}));
};
Mongoose.prototype.disconnect.$hasSideEffects = true;
/**
* Defines a model or retrieves it.
*
* Models defined on the `mongoose` instance are available to all connection created by the same `mongoose` instance.
*
* ####Example:
*
* var mongoose = require('mongoose');
*
* // define an Actor model with this mongoose instance
* mongoose.model('Actor', new Schema({ name: String }));
*
* // create a new connection
* var conn = mongoose.createConnection(..);
*
* // retrieve the Actor model
* var Actor = conn.model('Actor');
*
* _When no `collection` argument is passed, Mongoose produces a collection name by passing the model `name` to the [utils.toCollectionName](#utils_exports.toCollectionName) method. This method pluralizes the name. If you don't like this behavior, either pass a collection name or set your schemas collection name option._
*
* ####Example:
*
* var schema = new Schema({ name: String }, { collection: 'actor' });
*
* // or
*
* schema.set('collection', 'actor');
*
* // or
*
* var collectionName = 'actor'
* var M = mongoose.model('Actor', schema, collectionName)
*
* @param {String|Function} name model name or class extending Model
* @param {Schema} [schema]
* @param {String} [collection] name (optional, inferred from model name)
* @param {Boolean} [skipInit] whether to skip initialization (defaults to false)
* @api public
*/
Mongoose.prototype.model = function(name, schema, collection, skipInit) {
var model;
if (typeof name === 'function') {
model = name;
name = model.name;
if (!(model.prototype instanceof Model)) {
throw new mongoose.Error('The provided class ' + name + ' must extend Model');
}
}
if (typeof schema === 'string') {
collection = schema;
schema = false;
}
if (utils.isObject(schema) && !(schema.instanceOfSchema)) {
schema = new Schema(schema);
}
if (schema && !schema.instanceOfSchema) {
throw new Error('The 2nd parameter to `mongoose.model()` should be a ' +
'schema or a POJO');
}
if (typeof collection === 'boolean') {
skipInit = collection;
collection = null;
}
// handle internal options from connection.model()
var options;
if (skipInit && utils.isObject(skipInit)) {
options = skipInit;
skipInit = true;
} else {
options = {};
}
// look up schema for the collection.
if (!this.modelSchemas[name]) {
if (schema) {
// cache it so we only apply plugins once
this.modelSchemas[name] = schema;
} else {
throw new mongoose.Error.MissingSchemaError(name);
}
}
if (schema) {
this._applyPlugins(schema);
}
var sub;
// connection.model() may be passing a different schema for
// an existing model name. in this case don't read from cache.
if (this.models[name] && options.cache !== false) {
if (schema && schema.instanceOfSchema && schema !== this.models[name].schema) {
throw new mongoose.Error.OverwriteModelError(name);
}
if (collection) {
// subclass current model with alternate collection
model = this.models[name];
schema = model.prototype.schema;
sub = model.__subclass(this.connection, schema, collection);
// do not cache the sub model
return sub;
}
return this.models[name];
}
// ensure a schema exists
if (!schema) {
schema = this.modelSchemas[name];
if (!schema) {
throw new mongoose.Error.MissingSchemaError(name);
}
}
// Apply relevant "global" options to the schema
if (!('pluralization' in schema.options)) schema.options.pluralization = this.options.pluralization;
if (!collection) {
collection = schema.get('collection') || format(name, schema.options);
}
var connection = options.connection || this.connection;
model = this.Model.compile(model || name, schema, collection, connection, this);
if (!skipInit) {
model.init();
}
if (options.cache === false) {
return model;
}
this.models[name] = model;
return this.models[name];
};
Mongoose.prototype.model.$hasSideEffects = true;
/**
* Returns an array of model names created on this instance of Mongoose.
*
* ####Note:
*
* _Does not include names of models created using `connection.model()`._
*
* @api public
* @return {Array}
*/
Mongoose.prototype.modelNames = function() {
var names = Object.keys(this.models);
return names;
};
Mongoose.prototype.modelNames.$hasSideEffects = true;
/**
* Applies global plugins to `schema`.
*
* @param {Schema} schema
* @api private
*/
Mongoose.prototype._applyPlugins = function(schema) {
if (schema.$globalPluginsApplied) {
return;
}
var i;
var len;
for (i = 0, len = this.plugins.length; i < len; ++i) {
schema.plugin(this.plugins[i][0], this.plugins[i][1]);
}
schema.$globalPluginsApplied = true;
for (i = 0, len = schema.childSchemas.length; i < len; ++i) {
this._applyPlugins(schema.childSchemas[i].schema);
}
};
Mongoose.prototype._applyPlugins.$hasSideEffects = true;
/**
* Declares a global plugin executed on all Schemas.
*
* Equivalent to calling `.plugin(fn)` on each Schema you create.
*
* @param {Function} fn plugin callback
* @param {Object} [opts] optional options
* @return {Mongoose} this
* @see plugins ./plugins.html
* @api public
*/
Mongoose.prototype.plugin = function(fn, opts) {
this.plugins.push([fn, opts]);
return this;
};
Mongoose.prototype.plugin.$hasSideEffects = true;
/**
* The default connection of the mongoose module.
*
* ####Example:
*
* var mongoose = require('mongoose');
* mongoose.connect(...);
* mongoose.connection.on('error', cb);
*
* This is the connection used by default for every model created using [mongoose.model](#index_Mongoose-model).
*
* @property connection
* @return {Connection}
* @api public
*/
Mongoose.prototype.__defineGetter__('connection', function() {
return this.connections[0];
});
Mongoose.prototype.__defineSetter__('connection', function(v) {
if (v instanceof Connection) {
this.connections[0] = v;
this.models = v.models;
}
});
/*!
* Driver depentend APIs
*/
var driver = global.MONGOOSE_DRIVER_PATH || './drivers/node-mongodb-native';
/*!
* Connection
*/
var Connection = require(driver + '/connection');
/*!
* Collection
*/
var Collection = require(driver + '/collection');
/**
* The Mongoose Aggregate constructor
*
* @method Aggregate
* @api public
*/
Mongoose.prototype.Aggregate = Aggregate;
/**
* The Mongoose Collection constructor
*
* @method Collection
* @api public
*/
Mongoose.prototype.Collection = Collection;
/**
* The Mongoose [Connection](#connection_Connection) constructor
*
* @method Connection
* @api public
*/
Mongoose.prototype.Connection = Connection;
/**
* The Mongoose version
*
* @property version
* @api public
*/
Mongoose.prototype.version = pkg.version;
/**
* The Mongoose constructor
*
* The exports of the mongoose module is an instance of this class.
*
* ####Example:
*
* var mongoose = require('mongoose');
* var mongoose2 = new mongoose.Mongoose();
*
* @method Mongoose
* @api public
*/
Mongoose.prototype.Mongoose = Mongoose;
/**
* The Mongoose [Schema](#schema_Schema) constructor
*
* ####Example:
*
* var mongoose = require('mongoose');
* var Schema = mongoose.Schema;
* var CatSchema = new Schema(..);
*
* @method Schema
* @api public
*/
Mongoose.prototype.Schema = Schema;
/**
* The Mongoose [SchemaType](#schematype_SchemaType) constructor
*
* @method SchemaType
* @api public
*/
Mongoose.prototype.SchemaType = SchemaType;
/**
* The various Mongoose SchemaTypes.
*
* ####Note:
*
* _Alias of mongoose.Schema.Types for backwards compatibility._
*
* @property SchemaTypes
* @see Schema.SchemaTypes #schema_Schema.Types
* @api public
*/
Mongoose.prototype.SchemaTypes = Schema.Types;
/**
* The Mongoose [VirtualType](#virtualtype_VirtualType) constructor
*
* @method VirtualType
* @api public
*/
Mongoose.prototype.VirtualType = VirtualType;
/**
* The various Mongoose Types.
*
* ####Example:
*
* var mongoose = require('mongoose');
* var array = mongoose.Types.Array;
*
* ####Types:
*
* - [ObjectId](#types-objectid-js)
* - [Buffer](#types-buffer-js)
* - [SubDocument](#types-embedded-js)
* - [Array](#types-array-js)
* - [DocumentArray](#types-documentarray-js)
*
* Using this exposed access to the `ObjectId` type, we can construct ids on demand.
*
* var ObjectId = mongoose.Types.ObjectId;
* var id1 = new ObjectId;
*
* @property Types
* @api public
*/
Mongoose.prototype.Types = Types;
/**
* The Mongoose [Query](#query_Query) constructor.
*
* @method Query
* @api public
*/
Mongoose.prototype.Query = Query;
/**
* The Mongoose [Promise](#promise_Promise) constructor.
*
* @method Promise
* @api public
*/
Object.defineProperty(Mongoose.prototype, 'Promise', {
get: function() {
return PromiseProvider.get();
},
set: function(lib) {
PromiseProvider.set(lib);
}
});
/**
* Returns the current ES6-style promise constructor. In Mongoose 4.x,
* equivalent to `mongoose.Promise.ES6`, but will change once we get rid
* of the `.ES6` bit.
*
* @method Promise
* @api public
*/
Mongoose.prototype.getPromiseConstructor = function() {
return PromiseProvider.get().ES6;
};
/**
* Storage layer for mongoose promises
*
* @method PromiseProvider
* @api public
*/
Mongoose.prototype.PromiseProvider = PromiseProvider;
/**
* The Mongoose [Model](#model_Model) constructor.
*
* @method Model
* @api public
*/
Mongoose.prototype.Model = Model;
/**
* The Mongoose [Document](#document-js) constructor.
*
* @method Document
* @api public
*/
Mongoose.prototype.Document = Document;
/**
* The Mongoose DocumentProvider constructor.
*
* @method DocumentProvider
* @api public
*/
Mongoose.prototype.DocumentProvider = require('./document_provider');
/**
* The [MongooseError](#error_MongooseError) constructor.
*
* @method Error
* @api public
*/
Mongoose.prototype.Error = require('./error');
/**
* The Mongoose CastError constructor
*
* @method CastError
* @param {String} type The name of the type
* @param {Any} value The value that failed to cast
* @param {String} path The path `a.b.c` in the doc where this cast error occurred
* @param {Error} [reason] The original error that was thrown
* @api public
*/
Mongoose.prototype.CastError = require('./error/cast');
/**
* The [node-mongodb-native](https://github.com/mongodb/node-mongodb-native) driver Mongoose uses.
*
* @property mongo
* @api public
*/
Mongoose.prototype.mongo = require('mongodb');
/**
* The [mquery](https://github.com/aheckmann/mquery) query builder Mongoose uses.
*
* @property mquery
* @api public
*/
Mongoose.prototype.mquery = require('mquery');
/**
* Wraps the given Mongoose instance into a thenable (pseudo-promise). This
* is so `connect()` and `disconnect()` can return a thenable while maintaining
* backwards compatibility.
*
* @api private
*/
function MongooseThenable(mongoose, promise) {
var _this = this;
for (var key in mongoose) {
if (typeof mongoose[key] === 'function' && mongoose[key].$hasSideEffects) {
(function(key) {
_this[key] = function() {
return mongoose[key].apply(mongoose, arguments);
};
})(key);
} else if (['connection', 'connections'].indexOf(key) !== -1) {
_this[key] = mongoose[key];
}
}
this.$opPromise = promise;
}
MongooseThenable.prototype = new Mongoose;
/**
* Ability to use mongoose object as a pseudo-promise so `.connect().then()`
* and `.disconnect().then()` are viable.
*
* @param {Function} onFulfilled
* @param {Function} onRejected
* @return {Promise}
* @api private
*/
MongooseThenable.prototype.then = function(onFulfilled, onRejected) {
var Promise = PromiseProvider.get();
if (!this.$opPromise) {
return new Promise.ES6(function(resolve, reject) {
reject(new Error('Can only call `.then()` if connect() or disconnect() ' +
'has been called'));
}).then(onFulfilled, onRejected);
}
this.$opPromise.$hasHandler = true;
return this.$opPromise.then(onFulfilled, onRejected);
};
/**
* Ability to use mongoose object as a pseudo-promise so `.connect().then()`
* and `.disconnect().then()` are viable.
*
* @param {Function} onFulfilled
* @param {Function} onRejected
* @return {Promise}
* @api private
*/
MongooseThenable.prototype.catch = function(onRejected) {
return this.then(null, onRejected);
};
/*!
* The exports object is an instance of Mongoose.
*
* @api public
*/
var mongoose = module.exports = exports = new Mongoose;
+32
View File
@@ -0,0 +1,32 @@
/*!
* Dependencies
*/
var StateMachine = require('./statemachine');
var ActiveRoster = StateMachine.ctor('require', 'modify', 'init', 'default', 'ignore');
module.exports = exports = InternalCache;
function InternalCache() {
this.strictMode = undefined;
this.selected = undefined;
this.shardval = undefined;
this.saveError = undefined;
this.validationError = undefined;
this.adhocPaths = undefined;
this.removing = undefined;
this.inserting = undefined;
this.version = undefined;
this.getters = {};
this._id = undefined;
this.populate = undefined; // what we want to populate in this doc
this.populated = undefined;// the _ids that have been populated
this.wasPopulated = false; // if this doc was the result of a population
this.scope = undefined;
this.activePaths = new ActiveRoster;
this.pathsToScopes = {};
// embedded docs
this.ownerDocument = undefined;
this.fullPath = undefined;
}
+4104
View File
File diff suppressed because it is too large Load Diff

Some files were not shown because too many files have changed in this diff Show More