Skip to content

Commit

Permalink
feat(schema): add schema-level readConcern option to apply default re…
Browse files Browse the repository at this point in the history
…adConcern for all queries

Fix #14511
  • Loading branch information
vkarpov15 committed May 8, 2024
1 parent db29c08 commit df1c720
Show file tree
Hide file tree
Showing 6 changed files with 50 additions and 0 deletions.
19 changes: 19 additions & 0 deletions docs/guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -559,6 +559,7 @@ Valid options:
* [methods](#methods)
* [query](#query-helpers)
* [autoSearchIndex](#autoSearchIndex)
* [readConcern](#readConcern)

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

Expand Down Expand Up @@ -1473,6 +1474,24 @@ schema.searchIndex({
const Test = mongoose.model('Test', schema);
```

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

[Read concerns](https://www.mongodb.com/docs/manual/reference/read-concern/) are similar to [`writeConcern`](#writeConcern), but for read operations like `find()` and `findOne()`.
To set a default `readConcern`, pass the `readConcern` option to the schema constructor as follows.

```javascript
const eventSchema = new mongoose.Schema(
{ name: String },
{
readConcern: { level: 'available' } // <-- set default readConcern for all queries
}
);
```

<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
3 changes: 3 additions & 0 deletions lib/model.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ const applyEmbeddedDiscriminators = require('./helpers/discriminator/applyEmbedd
const applyHooks = require('./helpers/model/applyHooks');
const applyMethods = require('./helpers/model/applyMethods');
const applyProjection = require('./helpers/projection/applyProjection');
const applyReadConcern = require('./helpers/schema/applyReadConcern');
const applySchemaCollation = require('./helpers/indexes/applySchemaCollation');
const applyStaticHooks = require('./helpers/model/applyStaticHooks');
const applyStatics = require('./helpers/model/applyStatics');
Expand Down Expand Up @@ -417,6 +418,8 @@ Model.prototype.$__handleSave = function(options, callback) {
where[key] = val;
}
}

applyReadConcern(this.$__schema, optionsWithCustomValues);
this.constructor.collection.findOne(where, optionsWithCustomValues)
.then(documentExists => {
const matchedCount = !documentExists ? 0 : 1;
Expand Down
2 changes: 2 additions & 0 deletions lib/query.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const QueryCursor = require('./cursor/queryCursor');
const ValidationError = require('./error/validation');
const { applyGlobalMaxTimeMS, applyGlobalDiskUse } = require('./helpers/query/applyGlobalOption');
const handleReadPreferenceAliases = require('./helpers/query/handleReadPreferenceAliases');
const applyReadConcern = require('./helpers/schema/applyReadConcern');
const applyWriteConcern = require('./helpers/schema/applyWriteConcern');
const cast = require('./cast');
const castArrayFilters = require('./helpers/update/castArrayFilters');
Expand Down Expand Up @@ -1944,6 +1945,7 @@ Query.prototype._optionsForExec = function(model) {
if (!model) {
return options;
}
applyReadConcern(model.schema, options);
// Apply schema-level `writeConcern` option
applyWriteConcern(model.schema, options);

Expand Down
1 change: 1 addition & 0 deletions lib/schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ const numberRE = /^\d+$/;
* - [_id](https://mongoosejs.com/docs/guide.html#_id): bool - defaults to true
* - [minimize](https://mongoosejs.com/docs/guide.html#minimize): bool - controls [document#toObject](https://mongoosejs.com/docs/api/document.html#Document.prototype.toObject()) behavior when called manually - defaults to true
* - [read](https://mongoosejs.com/docs/guide.html#read): string
* - [readConcern](https://mongoosejs.com/docs/guide.html#readConcern): object - defaults to null, use to set a default [read concern](https://www.mongodb.com/docs/manual/reference/read-concern/) for all queries.
* - [writeConcern](https://mongoosejs.com/docs/guide.html#writeConcern): object - defaults to null, use to override [the MongoDB server's default write concern settings](https://www.mongodb.com/docs/manual/reference/write-concern/)
* - [shardKey](https://mongoosejs.com/docs/guide.html#shardKey): object - defaults to `null`
* - [strict](https://mongoosejs.com/docs/guide.html#strict): bool - defaults to true
Expand Down
21 changes: 21 additions & 0 deletions test/schema.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -3237,4 +3237,25 @@ describe('schema', function() {
assert.equal(doc.element, '#hero');
assert.ok(doc instanceof ClickedModel);
});

it('supports schema-level readConcern (gh-14511)', async function() {
const eventSchema = new mongoose.Schema({
name: String
}, { readConcern: { level: 'available' } });
const Event = db.model('Test', eventSchema);

let q = Event.find();
let options = q._optionsForExec();
assert.deepStrictEqual(options.readConcern, { level: 'available' });

q = Event.find().setOptions({ readConcern: { level: 'local' } });
options = q._optionsForExec();
assert.deepStrictEqual(options.readConcern, { level: 'local' });

q = Event.find().setOptions({ readConcern: null });
options = q._optionsForExec();
assert.deepStrictEqual(options.readConcern, null);

await q;
});
});
4 changes: 4 additions & 0 deletions types/schemaoptions.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,10 @@ declare module 'mongoose' {
* to all queries derived from a model.
*/
read?: string;
/**
* Set a default readConcern for all queries at the schema level
*/
readConcern?: { level: 'local' | 'available' | 'majority' | 'snapshot' | 'linearizable' }
/** Allows setting write concern at the schema level. */
writeConcern?: WriteConcern;
/** defaults to true. */
Expand Down

0 comments on commit df1c720

Please sign in to comment.