Skip to content

Commit

Permalink
Merge pull request #13613 from Automattic/7.4
Browse files Browse the repository at this point in the history
7.4
  • Loading branch information
vkarpov15 authored Jul 18, 2023
2 parents 8c17b91 + 8378c82 commit 52a6485
Show file tree
Hide file tree
Showing 51 changed files with 927 additions and 413 deletions.
110 changes: 16 additions & 94 deletions docs/deprecations.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,108 +9,30 @@ cause any problems for your application. Please [report any issues on GitHub](ht

To fix all deprecation warnings, follow the below steps:

* Replace `update()` with `updateOne()`, `updateMany()`, or `replaceOne()`
* Replace `remove()` with `deleteOne()` or `deleteMany()`.
* Replace `count()` with `countDocuments()`, unless you want to count how many documents are in the whole collection (no filter). In the latter case, use `estimatedDocumentCount()`.
* Replace `rawResult: true` with `includeResultMetadata: false` in `findOneAndUpdate()`, `findOneAndReplace()`, `findOneAndDelete()` calls.

Read below for more a more detailed description of each deprecation warning.

<h2 id="remove"><a href="#remove"><code>remove()</code></a></h2>
<h2 id="rawresult"><a href="#rawresult"><code>rawResult</code></a></h2>

The MongoDB driver's [`remove()` function](http://mongodb.github.io/node-mongodb-native/3.1/api/Collection.html#remove) is deprecated in favor of `deleteOne()` and `deleteMany()`. This is to comply with
the [MongoDB CRUD specification](https://github.com/mongodb/specifications/blob/master/source/crud/crud.rst),
which aims to provide a consistent API for CRUD operations across all MongoDB
drivers.

```txt
DeprecationWarning: collection.remove is deprecated. Use deleteOne,
deleteMany, or bulkWrite instead.
```

To remove this deprecation warning, replace any usage of `remove()` with
`deleteMany()`, *unless* you specify the [`single` option to `remove()`](api/model.html#model_Model-remove). The `single`
option limited `remove()` to deleting at most one document, so you should
replace `remove(filter, { single: true })` with `deleteOne(filter)`.
As of Mongoose 7.4.0, the `rawResult` option to `findOneAndUpdate()` is deprecated.
You should instead use the `includeResultMetadata` option, which the MongoDB Node.js driver's new option that replaces `rawResult`.

```javascript
// Replace this:
MyModel.remove({ foo: 'bar' });
// With this:
MyModel.deleteMany({ foo: 'bar' });

// Replace this:
MyModel.remove({ answer: 42 }, { single: true });
// With this:
MyModel.deleteOne({ answer: 42 });
```
const doc = await Test.findOneAndUpdate(
{ name: 'Test' },
{ name: 'Test Testerson' },
{ rawResult: true }
);

<h2 id="update"><a href="#update"><code>update()</code></a></h2>

Like `remove()`, the [`update()` function](api/model.html#model_Model-update) is deprecated in favor
of the more explicit [`updateOne()`](api/model.html#model_Model-updateOne), [`updateMany()`](api/model.html#model_Model-updateMany), and [`replaceOne()`](api/model.html#model_Model-replaceOne) functions. You should replace
`update()` with `updateOne()`, unless you use the [`multi` or `overwrite` options](api/model.html#model_Model-update).

```txt
collection.update is deprecated. Use updateOne, updateMany, or bulkWrite
instead.
```

```javascript
// Replace this:
MyModel.update({ foo: 'bar' }, { answer: 42 });
// With this:
MyModel.updateOne({ foo: 'bar' }, { answer: 42 });

// If you use `overwrite: true`, you should use `replaceOne()` instead:
MyModel.update(filter, update, { overwrite: true });
// Replace with this:
MyModel.replaceOne(filter, update);

// If you use `multi: true`, you should use `updateMany()` instead:
MyModel.update(filter, update, { multi: true });
// Replace with this:
MyModel.updateMany(filter, update);
const doc = await Test.findOneAndUpdate(
{ name: 'Test' },
{ name: 'Test Testerson' },
{ includeResultMetadata: false }
);
```

<h2 id="count"><a href="#count"><code>count()</code></a></h2>

The MongoDB server has deprecated the `count()` function in favor of two
separate functions, [`countDocuments()`](api/query.html#Query.prototype.countDocuments()) and
[`estimatedDocumentCount()`](api/query.html#Query.prototype.estimatedDocumentCount()).

```txt
DeprecationWarning: collection.count is deprecated, and will be removed in a future version. Use collection.countDocuments or collection.estimatedDocumentCount instead
```

The difference between the two is `countDocuments()` can accept a filter
parameter like [`find()`](api/query.html#Query.prototype.find()). The `estimatedDocumentCount()`
function is faster, but can only tell you the total number of documents in
a collection. You cannot pass a `filter` to `estimatedDocumentCount()`.

To migrate, replace `count()` with `countDocuments()` *unless* you do not
pass any arguments to `count()`. If you use `count()` to count all documents
in a collection as opposed to counting documents that match a query, use
`estimatedDocumentCount()` instead of `countDocuments()`.

```javascript
// Replace this:
MyModel.count({ answer: 42 });
// With this:
MyModel.countDocuments({ answer: 42 });

// If you're counting all documents in the collection, use
// `estimatedDocumentCount()` instead.
MyModel.count();
// Replace with:
MyModel.estimatedDocumentCount();

// Replace this:
MyModel.find({ answer: 42 }).count().exec();
// With this:
MyModel.find({ answer: 42 }).countDocuments().exec();

// Replace this:
MyModel.find().count().exec();
// With this, since there's no filter
MyModel.find().estimatedDocumentCount().exec();
```
The `rawResult` option only affects Mongoose; the MongoDB Node.js driver still returns the full result metadata, Mongoose just parses out the raw document.
The `includeResultMetadata` option also tells the MongoDB Node.js driver to only return the document, not the full `ModifyResult` object.
25 changes: 25 additions & 0 deletions docs/guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -526,6 +526,7 @@ Valid options:
* [skipVersioning](#skipVersioning)
* [timestamps](#timestamps)
* [storeSubdocValidationError](#storeSubdocValidationError)
* [collectionOptions](#collectionOptions)
* [methods](#methods)
* [query](#query-helpers)

Expand Down Expand Up @@ -1399,6 +1400,30 @@ const Parent = mongoose.model('Parent', parentSchema);
new Parent({ child: {} }).validateSync().errors;
```

<h2 id="collectionOptions">
<a href="#collectionOptions">
option: collectionOptions
</a>
</h2>

Options like [`collation`](#collation) and [`capped`](#capped) affect the options Mongoose passes to MongoDB when creating a new collection.
Mongoose schemas support most [MongoDB `createCollection()` options](https://www.mongodb.com/docs/manual/reference/method/db.createCollection/), but not all.
You can use the `collectionOptions` option to set any `createCollection()` options; Mongoose will use `collectionOptions` as the default values when calling `createCollection()` for your schema.

```javascript
const schema = new Schema({ name: String }, {
autoCreate: false,
collectionOptions: {
capped: true,
max: 1000
}
});
const Test = mongoose.model('Test', schema);

// Equivalent to `createCollection({ capped: true, max: 1000 })`
await Test.createCollection();
```

<h2 id="es6-classes"><a href="#es6-classes">With ES6 Classes</a></h2>

Schemas have a [`loadClass()` method](api/schema.html#schema_Schema-loadClass)
Expand Down
30 changes: 23 additions & 7 deletions docs/validation.md
Original file line number Diff line number Diff line change
Expand Up @@ -109,19 +109,35 @@ thrown.

## Cast Errors

Before running validators, Mongoose attempts to coerce values to the
correct type. This process is called *casting* the document. If
casting fails for a given path, the `error.errors` object will contain
a `CastError` object.
Before running validators, Mongoose attempts to coerce values to the correct type. This process is called *casting* the document.
If casting fails for a given path, the `error.errors` object will contain a `CastError` object.

Casting runs before validation, and validation does not run if casting
fails. That means your custom validators may assume `v` is `null`,
`undefined`, or an instance of the type specified in your schema.
Casting runs before validation, and validation does not run if casting fails.
That means your custom validators may assume `v` is `null`, `undefined`, or an instance of the type specified in your schema.

```acquit
[require:Cast Errors]
```

By default, Mongoose cast error messages look like `Cast to Number failed for value "pie" at path "numWheels"`.
You can overwrite Mongoose's default cast error message by the `cast` option on your SchemaType to a string as follows.

```acquit
[require:Cast Error Message Overwrite]
```

Mongoose's cast error message templating supports the following parameters:

* `{PATH}`: the path that failed to cast
* `{VALUE}`: a string representation of the value that failed to cast
* `{KIND}`: the type that Mongoose attempted to cast to, like `'String'` or `'Number'`

You can also define a function that Mongoose will call to get the cast error message as follows.

```acquit
[require:Cast Error Message Function Overwrite]
```

## Global SchemaType Validation

In addition to defining custom validators on individual schema paths, you can also configure a custom validator to run on every instance of a given `SchemaType`.
Expand Down
4 changes: 2 additions & 2 deletions lib/cast.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@ const Types = require('./schema/index');
const cast$expr = require('./helpers/query/cast$expr');
const castTextSearch = require('./schema/operators/text');
const get = require('./helpers/get');
const getConstructorName = require('./helpers/getConstructorName');
const getSchemaDiscriminatorByValue = require('./helpers/discriminator/getSchemaDiscriminatorByValue');
const isOperator = require('./helpers/query/isOperator');
const util = require('util');
const isObject = require('./helpers/isObject');
const isMongooseObject = require('./helpers/isMongooseObject');
const utils = require('./utils');

const ALLOWED_GEOWITHIN_GEOJSON_TYPES = ['Polygon', 'MultiPolygon'];

Expand Down Expand Up @@ -291,7 +291,7 @@ module.exports = function cast(schema, obj, options, context) {
}
} else if (val == null) {
continue;
} else if (getConstructorName(val) === 'Object') {
} else if (utils.isPOJO(val)) {
any$conditionals = Object.keys(val).some(isOperator);

if (!any$conditionals) {
Expand Down
Loading

0 comments on commit 52a6485

Please sign in to comment.