Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BREAKING CHANGE: use MongoDB node driver 6, drop support for rawResult option and findOneAndRemove() #13753

Merged
merged 12 commits into from
Sep 15, 2023
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ jobs:
strategy:
fail-fast: false
matrix:
node: [14, 16, 18, 20]
node: [16, 18, 20]
os: [ubuntu-20.04, ubuntu-22.04]
mongodb: [4.4.18, 5.0.14, 6.0.4]
include:
Expand Down Expand Up @@ -106,7 +106,7 @@ jobs:
- name: Setup Deno
uses: denoland/setup-deno@v1
with:
deno-version: v1.34.x
deno-version: v1.36.x
- run: deno --version
- run: npm install
- name: Run Deno tests
Expand Down
2 changes: 0 additions & 2 deletions docs/middleware.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ In query middleware functions, `this` refers to the query.
* [find](api/query.html#query_Query-find)
* [findOne](api/query.html#query_Query-findOne)
* [findOneAndDelete](api/query.html#query_Query-findOneAndDelete)
* [findOneAndRemove](api/query.html#query_Query-findOneAndRemove)
* [findOneAndReplace](api/query.html#query_Query-findOneAndReplace)
* [findOneAndUpdate](api/query.html#query_Query-findOneAndUpdate)
* [remove](api/model.html#model_Model-remove)
Expand Down Expand Up @@ -81,7 +80,6 @@ Here are the possible strings that can be passed to `pre()`
* find
* findOne
* findOneAndDelete
* findOneAndRemove
* findOneAndReplace
* findOneAndUpdate
* init
Expand Down
56 changes: 56 additions & 0 deletions docs/migrating_to_8.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Migrating from 7.x to 8.x

<style>
ul > li {
padding: 4px 0px;
}
</style>

There are several backwards-breaking changes
you should be aware of when migrating from Mongoose 7.x to Mongoose 8.x.

If you're still on Mongoose 6.x or earlier, please read the [Mongoose 6.x to 7.x migration guide](migrating_to_7.html) and upgrade to Mongoose 7.x first before upgrading to Mongoose 8.

* [Removed `rawResult` option for `findOneAndUpdate()`](#removed-rawresult-option-for-findoneandupdate)
* [Changed behavior for `findOneAndUpdate()` with `orFail()` and upsert](#changed-behavior-for-findoneandupdate-with-orfail-and-upsert)
* [MongoDB Node Driver 6.0](#mongodb-node-driver-6)
* [Removed `findOneAndRemove()`](#removed-findoneandremove)

<h2 id="removed-rawresult-option-for-findoneandupdate"><a href="#removed-rawresult-option-for-findoneandupdate">Removed <code>rawResult</code> option for <code>findOneAndUpdate()</code></a></h2>

The `rawResult` option for `findOneAndUpdate()`, `findOneAndReplace()`, and `findOneAndDelete()` has been replaced by the `includeResultMetadata` option.

```javascript
const filter = { name: 'Will Riker' };
const update = { age: 29 };

const res = await Character.findOneAndUpdate(filter, update, {
new: true,
upsert: true,
// Replace `rawResult: true` with `includeResultMetadata: true`
includeResultMetadata: true
});
```

`includeResultMetadata` in Mongoose 8 behaves identically to `rawResult`.

<h2 id="changed-behavior-for-findoneandupdate-with-orfail-and-upsert"><a href="#changed-behavior-for-findoneandupdate-with-orfail-and-upsert">Changed behavior for <code>findOneAndUpdate()</code> with <code>orFail()</code> and upsert</a></h2>

In Mongoose 7, `findOneAndUpdate(filter, update, { upsert: true }).orFail()` would throw a `DocumentNotFoundError` if a new document was upserted.
In other words, `findOneAndUpdate().orFail()` always threw an error if no document was found, even if a new document was upserted.

In Mongoose 8, `findOneAndUpdate(filter, update, { upsert: true }).orFail()` always succeeds.
`findOneAndUpdate().orFail()` now throws a `DocumentNotFoundError` if there's no document returned, rather than if no document was found.

<h2 id="mongodb-node-driver-6"><a href="#mongodb-node-driver-6">MongoDB Node Driver 6</a></h2>

Mongoose 8 uses [v6.x of the MongoDB Node driver](https://github.com/mongodb/node-mongodb-native/blob/main/HISTORY.md#600-2023-08-28).
There's a few noteable changes in MongoDB Node driver v6 that affect Mongoose:

1. The `ObjectId` constructor no longer accepts strings of length 12. In Mongoose 7, `new mongoose.Types.ObjectId('12charstring')` was perfectly valid. In Mongoose 8, `new mongoose.Types.ObjectId('12charstring')` throws an error.

<h2 id="removed-findoneandremove"><a href="#removed-findoneandremove">Removed <code>findOneAndRemove()</code></a></h2>

In Mongoose 7, `findOneAndRemove()` was an alias for `findOneAndDelete()` that Mongoose supported for backwards compatibility.
Mongoose 8 no longer supports `findOneAndRemove()`.
Use `findOneAndDelete()` instead.
2 changes: 1 addition & 1 deletion docs/models.md
Original file line number Diff line number Diff line change
Expand Up @@ -193,7 +193,7 @@ If you attempt to `save()` a document from a View, you will get an error from th

## Yet more

The [API docs](api/model.html#model_Model) cover many additional methods available like [count](api/model.html#model_Model-count), [mapReduce](api/model.html#model_Model-mapReduce), [aggregate](api/model.html#model_Model-aggregate), and [more](api/model.html#model_Model-findOneAndRemove).
The [API docs](api/model.html#model_Model) cover many additional methods available like [count](api/model.html#model_Model-count), [mapReduce](api/model.html#model_Model-mapReduce), [aggregate](api/model.html#model_Model-aggregate), and more.

## Next Up

Expand Down
1 change: 0 additions & 1 deletion docs/queries.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ Each of these functions returns a
* [`Model.findByIdAndUpdate()`](api.html#model_Model-findByIdAndUpdate)
* [`Model.findOne()`](api.html#model_Model-findOne)
* [`Model.findOneAndDelete()`](api.html#model_Model-findOneAndDelete)
* [`Model.findOneAndRemove()`](api.html#model_Model-findOneAndRemove)
* [`Model.findOneAndReplace()`](api.html#model_Model-findOneAndReplace)
* [`Model.findOneAndUpdate()`](api.html#model_Model-findOneAndUpdate)
* [`Model.replaceOne()`](api.html#model_Model-replaceOne)
Expand Down
1 change: 1 addition & 0 deletions docs/source/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ docs['docs/migration.md'] = { guide: true, title: 'Migration Guide', markdown: t
docs['docs/migrating_to_5.md'] = { guide: true, title: 'Migrating to Mongoose 5', markdown: true };
docs['docs/migrating_to_6.md'] = { guide: true, title: 'Migrating to Mongoose 6', markdown: true };
docs['docs/migrating_to_7.md'] = { guide: true, title: 'Migrating to Mongoose 7', markdown: true };
docs['docs/migrating_to_8.md'] = { guide: true, title: 'Migrating to Mongoose 8', markdown: true };
docs['docs/connections.md'] = { guide: true, title: 'Connecting to MongoDB', markdown: true };
docs['docs/lambda.md'] = { guide: true, title: 'Using Mongoose With AWS Lambda', markdown: true };
docs['docs/geojson.md'] = { guide: true, title: 'Using GeoJSON', acquit: true, markdown: true };
Expand Down
3 changes: 1 addition & 2 deletions lib/helpers/query/validOps.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,5 @@ module.exports = Object.freeze([
// Delete
'deleteMany',
'deleteOne',
'findOneAndDelete',
'findOneAndRemove'
'findOneAndDelete'
]);
114 changes: 5 additions & 109 deletions lib/model.js
Original file line number Diff line number Diff line change
Expand Up @@ -2358,7 +2358,7 @@ Model.$where = function $where() {
* @param {Object|String} [options.sort] if multiple docs are found by the conditions, sets the sort order to choose which doc to update.
* @param {Boolean} [options.runValidators] if true, runs [update validators](https://mongoosejs.com/docs/validation.html#update-validators) on this command. Update validators validate the update operation against the model's schema
* @param {Boolean} [options.setDefaultsOnInsert=true] If `setDefaultsOnInsert` and `upsert` are true, mongoose will apply the [defaults](https://mongoosejs.com/docs/defaults.html) specified in the model's schema if a new document is created
* @param {Boolean} [options.rawResult] if true, returns the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/4.9/interfaces/ModifyResult.html)
* @param {Boolean} [options.includeResultMetadata] if true, returns the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/4.9/interfaces/ModifyResult.html)
* @param {Boolean} [options.translateAliases=null] If set to `true`, translates any schema-defined aliases in `filter`, `projection`, `update`, and `distinct`. Throws an error if there are any conflicts where both alias and raw property are defined on the same object.
* @return {Query}
* @see Tutorial https://mongoosejs.com/docs/tutorials/findoneandupdate.html
Expand Down Expand Up @@ -2474,7 +2474,7 @@ function _decorateUpdateWithVersionKey(update, options, versionKey) {
* @param {Object|String} [options.sort] if multiple docs are found by the conditions, sets the sort order to choose which doc to update.
* @param {Boolean} [options.runValidators] if true, runs [update validators](https://mongoosejs.com/docs/validation.html#update-validators) on this command. Update validators validate the update operation against the model's schema
* @param {Boolean} [options.setDefaultsOnInsert=true] If `setDefaultsOnInsert` and `upsert` are true, mongoose will apply the [defaults](https://mongoosejs.com/docs/defaults.html) specified in the model's schema if a new document is created
* @param {Boolean} [options.rawResult] if true, returns the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/4.9/interfaces/ModifyResult.html)
* @param {Boolean} [options.includeResultMetadata] if true, returns the full [ModifyResult from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/4.9/interfaces/ModifyResult.html) rather than just the document
* @param {Boolean} [options.upsert=false] if true, and no documents found, insert a new document
* @param {Boolean} [options.new=false] if true, return the modified document rather than the original
* @param {Object|String} [options.select] sets the document fields to return.
Expand Down Expand Up @@ -2508,12 +2508,6 @@ Model.findByIdAndUpdate = function(id, update, options) {
*
* - `findOneAndDelete()`
*
* This function differs slightly from `Model.findOneAndRemove()` in that
* `findOneAndRemove()` becomes a [MongoDB `findAndModify()` command](https://www.mongodb.com/docs/manual/reference/method/db.collection.findAndModify/),
* as opposed to a `findOneAndDelete()` command. For most mongoose use cases,
* this distinction is purely pedantic. You should use `findOneAndDelete()`
* unless you have a good reason not to.
*
* #### Example:
*
* A.findOneAndDelete(conditions, options) // return Query
Expand All @@ -2535,7 +2529,7 @@ Model.findByIdAndUpdate = function(id, update, options) {
* @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](https://mongoosejs.com/docs/guide.html#strict)
* @param {Object|String|String[]} [options.projection=null] optional fields to return, see [`Query.prototype.select()`](https://mongoosejs.com/docs/api/query.html#Query.prototype.select())
* @param {ClientSession} [options.session=null] The session associated with this query. See [transactions docs](https://mongoosejs.com/docs/transactions.html).
* @param {Boolean} [options.rawResult] if true, returns the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/4.9/interfaces/ModifyResult.html)
* @param {Boolean} [options.includeResultMetadata] if true, returns the full [ModifyResult from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/4.9/interfaces/ModifyResult.html) rather than just the document
* @param {Object|String} [options.sort] if multiple docs are found by the conditions, sets the sort order to choose which doc to update.
* @param {Object|String} [options.select] sets the document fields to return.
* @param {Number} [options.maxTimeMS] puts a time limit on the query - requires mongodb >= 2.6.0
Expand Down Expand Up @@ -2577,7 +2571,7 @@ Model.findOneAndDelete = function(conditions, options) {
* @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](https://mongoosejs.com/docs/guide.html#strict)
* @param {Boolean} [options.translateAliases=null] If set to `true`, translates any schema-defined aliases in `filter`, `projection`, `update`, and `distinct`. Throws an error if there are any conflicts where both alias and raw property are defined on the same object.
* @return {Query}
* @see Model.findOneAndRemove https://mongoosejs.com/docs/api/model.html#Model.findOneAndRemove()
* @see Model.findOneAndDelete https://mongoosejs.com/docs/api/model.html#Model.findOneAndDelete()
* @see mongodb https://www.mongodb.com/docs/manual/reference/command/findAndModify/
*/

Expand Down Expand Up @@ -2616,7 +2610,7 @@ Model.findByIdAndDelete = function(id, options) {
* @param {Boolean} [options.timestamps=null] If set to `false` and [schema-level timestamps](https://mongoosejs.com/docs/guide.html#timestamps) are enabled, skip timestamps for this update. Note that this allows you to overwrite timestamps. Does nothing if schema-level timestamps are not set.
* @param {Object|String|String[]} [options.projection=null] optional fields to return, see [`Query.prototype.select()`](https://mongoosejs.com/docs/api/query.html#Query.prototype.select())
* @param {Object|String} [options.sort] if multiple docs are found by the conditions, sets the sort order to choose which doc to update.
* @param {Boolean} [options.rawResult] if true, returns the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/4.9/interfaces/ModifyResult.html)
* @param {Boolean} [options.includeResultMetadata] if true, returns the full [ModifyResult from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/4.9/interfaces/ModifyResult.html) rather than just the document
* @param {Object|String} [options.select] sets the document fields to return.
* @param {Number} [options.maxTimeMS] puts a time limit on the query - requires mongodb >= 2.6.0
* @param {Boolean} [options.translateAliases=null] If set to `true`, translates any schema-defined aliases in `filter`, `projection`, `update`, and `distinct`. Throws an error if there are any conflicts where both alias and raw property are defined on the same object.
Expand All @@ -2643,104 +2637,6 @@ Model.findOneAndReplace = function(filter, replacement, options) {
return mq.findOneAndReplace(filter, replacement, options);
};

/**
* Issue a mongodb findOneAndRemove command.
*
* Finds a matching document, removes it, and returns the found document (if any).
*
* This function triggers the following middleware.
*
* - `findOneAndRemove()`
*
* #### Example:
*
* A.findOneAndRemove(conditions, options) // return Query
* A.findOneAndRemove(conditions) // returns Query
* A.findOneAndRemove() // returns Query
*
* `findOneAndX` and `findByIdAndX` functions support limited validation. You can
* enable validation by setting the `runValidators` option.
*
* If you need full-fledged validation, use the traditional approach of first
* retrieving the document.
*
* const doc = await Model.findById(id);
* doc.name = 'jason bourne';
* await doc.save();
*
* @param {Object} conditions
* @param {Object} [options] optional see [`Query.prototype.setOptions()`](https://mongoosejs.com/docs/api/query.html#Query.prototype.setOptions())
* @param {ClientSession} [options.session=null] The session associated with this query. See [transactions docs](https://mongoosejs.com/docs/transactions.html).
* @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](https://mongoosejs.com/docs/guide.html#strict)
* @param {Object|String|String[]} [options.projection=null] optional fields to return, see [`Query.prototype.select()`](https://mongoosejs.com/docs/api/query.html#Query.prototype.select())
* @param {Object|String} [options.sort] if multiple docs are found by the conditions, sets the sort order to choose which doc to update.
* @param {Boolean} [options.rawResult] if true, returns the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/4.9/interfaces/ModifyResult.html)
* @param {Object|String} [options.select] sets the document fields to return.
* @param {Number} [options.maxTimeMS] puts a time limit on the query - requires mongodb >= 2.6.0
* @param {Boolean} [options.translateAliases=null] If set to `true`, translates any schema-defined aliases in `filter`, `projection`, `update`, and `distinct`. Throws an error if there are any conflicts where both alias and raw property are defined on the same object.
* @return {Query}
* @see mongodb https://www.mongodb.com/docs/manual/reference/command/findAndModify/
* @api public
*/

Model.findOneAndRemove = function(conditions, options) {
_checkContext(this, 'findOneAndRemove');

if (typeof arguments[0] === 'function' || typeof arguments[1] === 'function' || typeof arguments[2] === 'function' || typeof arguments[3] === 'function') {
throw new MongooseError('Model.findOneAndRemove() no longer accepts a callback');
}

let fields;
if (options) {
fields = options.select;
options.select = undefined;
}

const mq = new this.Query({}, {}, this, this.$__collection);
mq.select(fields);

return mq.findOneAndRemove(conditions, options);
};

/**
* Issue a mongodb findOneAndRemove command by a document's _id field. `findByIdAndRemove(id, ...)` is equivalent to `findOneAndRemove({ _id: id }, ...)`.
*
* Finds a matching document, removes it, and returns the found document (if any).
*
* This function triggers the following middleware.
*
* - `findOneAndRemove()`
*
* #### Example:
*
* A.findByIdAndRemove(id, options) // return Query
* A.findByIdAndRemove(id) // returns Query
* A.findByIdAndRemove() // returns Query
*
* @param {Object|Number|String} id value of `_id` to query by
* @param {Object} [options] optional see [`Query.prototype.setOptions()`](https://mongoosejs.com/docs/api/query.html#Query.prototype.setOptions())
* @param {Boolean|String} [options.strict] overwrites the schema's [strict mode option](https://mongoosejs.com/docs/guide.html#strict)
* @param {ClientSession} [options.session=null] The session associated with this query. See [transactions docs](https://mongoosejs.com/docs/transactions.html).
* @param {Object|String|String[]} [options.projection=null] optional fields to return, see [`Query.prototype.select()`](https://mongoosejs.com/docs/api/query.html#Query.prototype.select())
* @param {Object|String} [options.sort] if multiple docs are found by the conditions, sets the sort order to choose which doc to update.
* @param {Boolean} [options.rawResult] if true, returns the [raw result from the MongoDB driver](https://mongodb.github.io/node-mongodb-native/4.9/interfaces/ModifyResult.html)
* @param {Object|String} [options.select] sets the document fields to return.
* @param {Boolean} [options.translateAliases=null] If set to `true`, translates any schema-defined aliases in `filter`, `projection`, `update`, and `distinct`. Throws an error if there are any conflicts where both alias and raw property are defined on the same object.
* @return {Query}
* @see Model.findOneAndRemove https://mongoosejs.com/docs/api/model.html#Model.findOneAndRemove()
* @see mongodb https://www.mongodb.com/docs/manual/reference/command/findAndModify/
*/

Model.findByIdAndRemove = function(id, options) {
_checkContext(this, 'findByIdAndRemove');

if (typeof arguments[0] === 'function' || typeof arguments[1] === 'function' || typeof arguments[2] === 'function' || typeof arguments[3] === 'function') {
throw new MongooseError('Model.findByIdAndRemove() no longer accepts a callback');
}

return this.findOneAndRemove({ _id: id }, options);
};

/**
* Shortcut for saving one or more documents to the database.
* `MyModel.create(docs)` does `new MyModel(doc).save()` for every doc in
Expand Down