Skip to content

Commit

Permalink
Merge branch '4.10' into 4569
Browse files Browse the repository at this point in the history
  • Loading branch information
vkarpov15 committed May 15, 2017
2 parents 173d72e + 636e922 commit 214323d
Show file tree
Hide file tree
Showing 53 changed files with 1,972 additions and 553 deletions.
2 changes: 2 additions & 0 deletions .eslintignore
Expand Up @@ -2,3 +2,5 @@ docs/
bin/
test/triage/
test/model.discriminator.test.js
tools/
test/es6/
1 change: 0 additions & 1 deletion .gitignore
Expand Up @@ -10,7 +10,6 @@ benchmarks/v8.log
.DS_Store
docs/*.json
docs/source/_docs
docs/*.html
tags
test/triage/*.js
/.idea
Expand Down
3 changes: 3 additions & 0 deletions .travis.yml
Expand Up @@ -13,3 +13,6 @@ before_script:
- tar -zxvf mongodb-linux-x86_64-2.6.11.tgz
- mkdir -p ./data/db
- ./mongodb-linux-x86_64-2.6.11/bin/mongod --fork --nopreallocj --dbpath ./data/db --syslog --port 27017
script:
- npm test
- npm run lint
54 changes: 54 additions & 0 deletions History.md
@@ -1,3 +1,57 @@
4.9.9 / 2017-05-13
==================
* docs: correct value for Query#regex() #5230
* fix(connection): don't throw if .catch() on open() promise #5229
* fix(schema): allow update with $currentDate for updatedAt to succeed #5222
* fix(model): versioning doesn't fail if version key undefined #5221 [basileos](https://github.com/basileos)
* fix(document): don't emit model error if callback specified for consistency with docs #5216
* fix(document): handle errors in subdoc pre validate #5215

4.9.8 / 2017-05-07
==================
* docs(subdocs): rewrite subdocs guide #5217
* fix(document): avoid circular JSON if error in doc array under single nested subdoc #5208
* fix(document): set intermediate empty objects for deeply nested undefined paths before path itself #5206
* fix(schema): throw error if first param to schema.plugin() is not a function #5201
* perf(document): major speedup in validating subdocs (50x in some cases) #5191

4.9.7 / 2017-04-30
==================
* docs: fix typo #5204 [phutchins](https://github.com/phutchins)
* fix(schema): ensure correct path for deeply nested schema indexes #5199
* fix(schema): make remove a reserved name #5197
* fix(model): handle Decimal type in insertMany correctly #5190
* fix: upgrade kareem to handle async pre hooks correctly #5188
* docs: add details about unique not being a validator #5179
* fix(validation): handle returning a promise with isAsync: true #5171

4.9.6 / 2017-04-23
==================
* fix: update `parentArray` references when directly assigning document arrays #5192 [jhob](https://github.com/jhob)
* docs: improve schematype validator docs #5178 [milesbarr](https://github.com/milesbarr)
* fix(model): modify discriminator() class in place #5175
* fix(model): handle bulkWrite updateMany casting #5172 [tzellman](https://github.com/tzellman)
* docs(model): fix replaceOne example for bulkWrite #5168
* fix(document): don't create a new array subdoc when creating schema array #5162
* fix(model): merge query hooks from discriminators #5147
* fix(document): add parent() function to subdocument to match array subdoc #5134

4.9.5 / 2017-04-16
==================
* fix(query): correct $pullAll casting of null #5164 [Sebmaster](https://github.com/Sebmaster)
* docs: add advanced schemas docs for loadClass #5157
* fix(document): handle null/undefined gracefully in applyGetters() #5143
* fix(model): add resolveToObject option for mapReduce with ES6 promises #4945

4.9.4 / 2017-04-09
==================
* fix(schema): clone query middleware correctly #5153 #5141 [clozanosanchez](https://github.com/clozanosanchez)
* docs(aggregate): fix typo #5142
* fix(query): cast .$ update to underlying array type #5130
* fix(populate): don't mutate populate result in place #5128
* fix(query): handle $setOnInsert consistent with $set #5126
* docs(query): add strict mode option for findOneAndUpdate #5108

4.9.3 / 2017-04-02
==================
* docs: document.js fixes for functions prepended with `$` #5131 [krmannix](https://github.com/krmannix)
Expand Down
38 changes: 38 additions & 0 deletions docs/faq.jade
Expand Up @@ -30,6 +30,44 @@ block content
doc.array[3] = 'changed';
doc.markModified('array');
doc.save();

hr#unique-doesnt-work
:markdown
**Q**. I declared a schema property as `unique` but I can still save duplicates. What gives?

**A**. Mongoose doesn't handle `unique` on it's own, `{ name: { type: String, unique: true } }`
just a shorthand for creating a [MongoDB unique index on `name`](https://docs.mongodb.com/manual/core/index-unique/).
For example, if MongoDB doesn't already have a unique index on `name`, the below code will not error despite the fact that `unique` is true.
:js
var schema = new mongoose.Schema({
name: { type: String, unique: true }
});
var Model = db.model('Test', schema);

Model.create([{ name: 'Val' }, { name: 'Val' }], function(err) {
console.log(err); // No error, unless index was already built
});
:markdown
However, if you wait for the index to build using the `Model.on('index')` event, attempts to save duplicates will correctly error.
:js
var schema = new mongoose.Schema({
name: { type: String, unique: true }
});
var Model = db.model('Test', schema);

Model.on('index', function(err) { // <-- Wait for model's indexes to finish
assert.ifError(err);
Model.create([{ name: 'Val' }, { name: 'Val' }], function(err) {
console.log(err);
});
});
:markdown
MongoDB persists indexes, so you only need to rebuild indexes if you're starting
with a fresh database or you ran `db.dropDatabase()`. In a production environment,
you should [create your indexes using the MongoDB shell])(https://docs.mongodb.com/manual/reference/method/db.collection.createIndex/)
rather than relying on mongoose to do it for you. The `unique` option for schemas is
convenient for development and documentation, but mongoose is *not* an index management solution.

hr#date_changes
:markdown
**Q**. Why don't in-place modifications to date objects
Expand Down
9 changes: 6 additions & 3 deletions docs/includes/nav.jade
Expand Up @@ -22,6 +22,12 @@ ul
a(href="./schematypes.html")
span schema
| types
li.custom-schema-types
a(href="./customschematypes.html")
| custom schema types
li.advanced-schemas
a(href="./advanced_schemas.html")
| advanced usage
li
a(href="./models.html")
| models
Expand Down Expand Up @@ -68,9 +74,6 @@ ul
li
a(href="./browser.html")
| schemas in the browser
li
a(href="./customschematypes.html")
| custom schema types
li
a(href="./compatibility.html")
| MongoDB Version Compatibility
Expand Down
5 changes: 5 additions & 0 deletions docs/source/acquit.js
Expand Up @@ -30,6 +30,11 @@ var files = [
input: 'test/docs/validation.test.js',
output: 'validation.html',
title: 'Validation'
},
{
input: 'test/docs/schemas.test.es6.js',
output: 'advanced_schemas.html',
title: 'Advanced Schemas'
}
];

Expand Down
126 changes: 83 additions & 43 deletions docs/subdocs.jade
Expand Up @@ -3,47 +3,101 @@ extends layout
block content
h2 Sub Docs
:markdown
[Sub-documents](./api.html#types-embedded-js) are docs with schemas of
their own which are elements of a parent document array:
Subdocuments are documents embedded in other documents. In Mongoose, this
means you can nest schemas in other schemas. Mongoose has two
distinct notions of subdocuments: arrays of subdocuments and single nested
subdocuments.
:js
var childSchema = new Schema({ name: 'string' });

var parentSchema = new Schema({
children: [childSchema]
})
// Array of subdocuments
children: [childSchema],
// Single nested subdocuments. Caveat: single nested subdocs only work
// in mongoose >= 4.2.0
child: childSchema
});

:markdown
Sub-documents enjoy all the same features as normal
[documents](./api.html#document-js). The only difference is that they are
Subdocuments are similar to normal documents. Nested schemas can have
[middleware](http://mongoosejs.com/docs/middleware.html), [custom validation logic](http://mongoosejs.com/docs/middleware.html),
virtuals, and any other feature top-level schemas can use. The major
difference is that subdocuments are
not saved individually, they are saved whenever their top-level parent
document is saved.
:js
var Parent = mongoose.model('Parent', parentSchema);
var parent = new Parent({ children: [{ name: 'Matt' }, { name: 'Sarah' }] })
parent.children[0].name = 'Matthew';

// `parent.children[0].save()` is a no-op, it triggers middleware but
// does **not** actually save the subdocument. You need to save the parent
// doc.
parent.save(callback);

:markdown
If an error occurs in a sub-document's middleware, it is bubbled up to the `save()` callback of the parent, so error handling is a snap!
Subdocuments have `save` and `validate` [middleware](http://mongoosejs.com/docs/middleware.html)
just like top-level documents. Calling `save()` on the parent document triggers
the `save()` middleware for all its subdocuments, and the same for `validate()`
middleware.

:js
childSchema.pre('save', function (next) {
if ('invalid' == this.name) return next(new Error('#sadpanda'));
if ('invalid' == this.name) {
return next(new Error('#sadpanda'));
}
next();
});

var parent = new Parent({ children: [{ name: 'invalid' }] });
parent.save(function (err) {
console.log(err.message) // #sadpanda
})
});

:markdown
Subdocuments' `pre('save')` and `pre('validate')` middleware execute
**before** the top-level document's `pre('save')` but **after** the
top-level document's `pre('validate')` middleware. This is because validating
before `save()` is actually a piece of built-in middleware.

:js
// Below code will print out 1-4 in order
var childSchema = new mongoose.Schema({ name: 'string' });

childSchema.pre('validate', function(next) {
console.log('2');
next();
});

childSchema.pre('save', function(next) {
console.log('3');
next();
});

var parentSchema = new mongoose.Schema({
child: childSchema,
});

parentSchema.pre('validate', function(next) {
console.log('1');
next();
});

parentSchema.pre('save', function(next) {
console.log('4');
next();
});


h3 Finding a sub-document
:markdown
Each document has an `_id`. DocumentArrays have a special [id](./api.html#types_documentarray_MongooseDocumentArray-id) method for looking up a document by its `_id`.
Each subdocument has an `_id` by default. Mongoose document arrays have a
special [id](./api.html#types_documentarray_MongooseDocumentArray-id) method
for searching a document array to find a document with a given `_id`.
:js
var doc = parent.children.id(_id);

h3 Adding sub-docs
h3 Adding sub-docs to arrays
:markdown
MongooseArray methods such as
[push](./api.html#types_array_MongooseArray.push),
Expand Down Expand Up @@ -71,50 +125,36 @@ block content
:js
var newdoc = parent.children.create({ name: 'Aaron' });

h3 Removing docs
h3 Removing subdocs
:markdown
Each sub-document has it's own
[remove](./api.html#types_embedded_EmbeddedDocument-remove) method.
Each subdocument has it's own
[remove](./api.html#types_embedded_EmbeddedDocument-remove) method. For
an array subdocument, this is equivalent to calling `.pull()` on the
subdocument. For a single nested subdocument, `remove()` is equivalent
to setting the subdocument to `null`.
:js
var doc = parent.children.id(_id).remove();
// Equivalent to `parent.children.pull(_id)`
parent.children.id(_id).remove();
// Equivalent to `parent.child = null`
parent.child.remove();
parent.save(function (err) {
if (err) return handleError(err);
console.log('the sub-doc was removed')
console.log('the subdocs were removed');
});

h4#altsyntax Alternate declaration syntax
h4#altsyntax Alternate declaration syntax for arrays
:markdown
If you don't need access to the sub-document schema instance,
you may also declare sub-docs by simply passing an object literal:
If you create a schema with an array of objects, mongoose will automatically
convert the object to a schema for you:
:js
var parentSchema = new Schema({
children: [{ name: 'string' }]
})

h4#single-embedded Single Embedded Subdocs
:markdown
**New in 4.2.0**

You can also embed schemas without using arrays.
:js
var childSchema = new Schema({ name: 'string' });

var parentSchema = new Schema({
child: childSchema
});
:markdown
A single embedded sub-document behaves similarly to an embedded array.
It only gets saved when the parent document gets saved and its pre/post
document middleware gets executed.
:js
childSchema.pre('save', function(next) {
console.log(this.name); // prints 'Leia'
// Equivalent
var parentSchema = new Schema({
children: [new Schema({ name: 'string' })]
});
var Parent = mongoose.model('Parent', parentSchema);
var parent = new Parent({ child: { name: 'Luke' } })
parent.child.name = 'Leia';
parent.save(callback); // Triggers the pre middleware.


h3#next Next Up
:markdown
Now that we've covered `Sub-documents`, let's take a look at
Expand Down
2 changes: 1 addition & 1 deletion lib/aggregate.js
Expand Up @@ -171,7 +171,7 @@ Aggregate.prototype.project = function(arg) {
*
* ####Examples:
*
* aggregate.match({ department: { $in: [ "sales", "engineering" } } });
* aggregate.match({ department: { $in: [ "sales", "engineering" ] } });
*
* @see $match http://docs.mongodb.org/manual/reference/aggregation/match/
* @method match
Expand Down
3 changes: 3 additions & 0 deletions lib/cast.js
Expand Up @@ -179,6 +179,9 @@ module.exports = function cast(schema, obj, options) {
}
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;
Expand Down

0 comments on commit 214323d

Please sign in to comment.