From f08a4bddadc6289ccb1cede1d96914e758b30acb Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Fri, 1 Feb 2019 12:03:58 -0500 Subject: [PATCH] docs(documents): improve explanation of documents and use more modern syntax Fix #7463 --- docs/documents.jade | 124 +++++++++++++++++++++++++++----------------- 1 file changed, 75 insertions(+), 49 deletions(-) diff --git a/docs/documents.jade b/docs/documents.jade index 80595a19786..2f3198c9c53 100644 --- a/docs/documents.jade +++ b/docs/documents.jade @@ -23,85 +23,111 @@ block content [Model](./models.html). - ### Retrieving + ### Documents vs Models - There are many ways to retrieve documents from MongoDB. We won't cover that - in this section. See the chapter on [querying](./queries.html) for detail. + [Document](api.html#Document) and [Model](api.html#Model) are distinct + classes in Mongoose. The Model class is a subclass of the Document class. + When you use the [Model constructor](api.html#Model), you create a + new document. - ### Updating + ```javascript + const MyModel = mongoose.model('Test', new Schema({ name: String })); + const doc = new MyModel(); + + doc instanceof MyModel; // true + doc instanceof mongoose.Model; // true + doc instanceof mongoose.Document; // true + ``` + + In Mongoose, a "document" generally means an instance of a model. + You should not have to create an instance of the Document class without + going through a model. + + ### Retrieving - There are a number of ways to update documents. We'll first look at a - traditional approach using [findById](./api.html#model_Model.findById): + When you load documents from MongoDB using model functions like [`findOne()`](api.html#model_Model.findOne), + you get a Mongoose document back. ```javascript - Tank.findById(id, function (err, tank) { - if (err) return handleError(err); + const doc = await MyModel.findOne(); - tank.size = 'large'; - tank.save(function (err, updatedTank) { - if (err) return handleError(err); - res.send(updatedTank); - }); - }); + doc instanceof MyModel; // true + doc instanceof mongoose.Model; // true + doc instanceof mongoose.Document; // true ``` - You can also use [`.set()`](./api.html#document_Document-set) - to modify documents. Under the hood, `tank.size = 'large';` becomes - `tank.set({ size: 'large' })`. + ### Updating + + Mongoose documents track changes. You can modify a document using vanilla + JavaScript assignments and Mongoose will convert it into [MongoDB update operators](https://docs.mongodb.com/manual/reference/operator/update/). ```javascript - Tank.findById(id, function (err, tank) { - if (err) return handleError(err); + doc.name = 'foo'; - tank.set({ size: 'large' }); - tank.save(function (err, updatedTank) { - if (err) return handleError(err); - res.send(updatedTank); - }); - }); + // Mongoose sends a `updateOne({ _id: doc._id }, { $set: { name: 'foo' } })` + // to MongoDB. + await doc.save(); ``` - This approach involves first retrieving the document from Mongo, then - issuing an update command (triggered by calling `save`). However, if we - don't need the document returned in our application and merely want to - update a property in the database directly, - [Model#update](./api.html#model_Model.update) is right for us: + The [`save()`](api.html#model_Model-save) function is generally the right way to update a document with + Mongoose. With `save()`, you get full [validation](validation.html) + and [middleware](middleware.html). + + For cases when `save()` isn't flexible enough, Mongoose lets you create + your own [MongoDB updates](https://docs.mongodb.com/manual/reference/operator/update/) + with casting, [middleware](middleware.html#notes), and [limited validation](validation.html#update-validators). ```javascript - Tank.update({ _id: id }, { $set: { size: 'large' }}, callback); + // Update all documents in the `mymodels` collection + await MyModel.updateMany({}, { $set: { name: 'foo' } }); ``` - If we do need the document returned in our application there is another, - often [better](./api.html#model_Model.findByIdAndUpdate), option: + _Note that `update()`, `updateMany()`, `findOneAndUpdate()`, etc. do *not* + execute `save()` middleware. If you need save middleware and full validation, + first query for the document and then `save()` it._ + + ### Validating + + Documents are casted validated before they are saved. Mongoose first casts + values to the specified type and then validates them. Internally, Mongoose + calls the document's [`validate()` method](api.html#document_Document-validate) + before saving. ```javascript - Tank.findByIdAndUpdate(id, { $set: { size: 'large' }}, { new: true }, function (err, tank) { - if (err) return handleError(err); - res.send(tank); - }); + const schema = new Schema({ name: String, age: { type: Number, min: 0 } }); + const Person = mongoose.model('Person', schema); + + let p = new Person({ name: 'foo', age: 'bar' }); + // Cast to Number failed for value "bar" at path "age" + await p.validate(); + + let p2 = new Person({ name: 'foo', age: -1 }); + // Path `age` (-1) is less than minimum allowed value (0). + await p2.validate(); ``` - The `findAndUpdate/Remove` static methods all make a change to at most one - document, and return it with just one call to the database. There - [are](./api.html#model_Model.findByIdAndRemove) - [several](./api.html#model_Model.findOneAndUpdate) - [variations](./api.html#model_Model.findOneAndRemove) on the - [findAndModify](http://www.mongodb.org/display/DOCS/findAndModify+Command) - theme. Read the [API](./api.html) docs for more detail. + Mongoose also supports limited validation on updates using the [`runValidators` option](validation.html#update-validators). + Mongoose casts parameters to query functions like `findOne()`, `updateOne()` + by default. However, Mongoose does _not_ run validation on query function + parameters by default. You need to set `runValidators: true` for Mongoose + to validate. - _Note that `findAndUpdate/Remove` do *not* execute any hooks or validation before making the change in the database. You can use the [`runValidators` option](/docs/validation.html#update-validators) to access a limited subset of document validation. However, if you need hooks and full document validation, first query for the document and then `save()` it._ + ```javascript + // Cast to number failed for value "bar" at path "age" + await Person.updateOne({}, { age: 'bar' }); - ### Validating + // Path `age` (-1) is less than minimum allowed value (0). + await Person.updateOne({}, { age: -1 }, { runValidators: true }); + ``` - Documents are validated before they are saved. Read the - [api](./api.html#document_Document-validate) docs or the - [validation](./validation.html) chapter for detail. + Read the [validation](./validation.html) guide for more details. ### Overwriting