Skip to content

Commit 434dac8

Browse files
authored
Merge pull request #14546 from sderrow/bulk-write-timestamps-fix
Improved timestamps option handling in bulkWrite
2 parents 286c7d1 + f463240 commit 434dac8

File tree

3 files changed

+39
-9
lines changed

3 files changed

+39
-9
lines changed

lib/helpers/model/castBulkWrite.js

Lines changed: 27 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ module.exports = function castBulkWrite(originalModel, op, options) {
2929
const model = decideModelByObject(originalModel, op['insertOne']['document']);
3030

3131
const doc = new model(op['insertOne']['document']);
32-
if (model.schema.options.timestamps && options.timestamps !== false) {
32+
if (model.schema.options.timestamps && getTimestampsOpt(op['insertOne'], options)) {
3333
doc.initializeTimestamps();
3434
}
3535
if (options.session != null) {
@@ -69,13 +69,15 @@ module.exports = function castBulkWrite(originalModel, op, options) {
6969

7070
_addDiscriminatorToObject(schema, op['updateOne']['filter']);
7171

72-
if (model.schema.$timestamps != null && op['updateOne'].timestamps !== false) {
72+
const doInitTimestamps = getTimestampsOpt(op['updateOne'], options);
73+
74+
if (model.schema.$timestamps != null && doInitTimestamps) {
7375
const createdAt = model.schema.$timestamps.createdAt;
7476
const updatedAt = model.schema.$timestamps.updatedAt;
7577
applyTimestampsToUpdate(now, createdAt, updatedAt, update, {});
7678
}
7779

78-
if (op['updateOne'].timestamps !== false) {
80+
if (doInitTimestamps) {
7981
applyTimestampsToChildren(now, update, model.schema);
8082
}
8183

@@ -134,12 +136,14 @@ module.exports = function castBulkWrite(originalModel, op, options) {
134136
});
135137
}
136138

137-
if (model.schema.$timestamps != null && op['updateMany'].timestamps !== false) {
139+
const doInitTimestamps = getTimestampsOpt(op['updateMany'], options);
140+
141+
if (model.schema.$timestamps != null && doInitTimestamps) {
138142
const createdAt = model.schema.$timestamps.createdAt;
139143
const updatedAt = model.schema.$timestamps.updatedAt;
140144
applyTimestampsToUpdate(now, createdAt, updatedAt, op['updateMany']['update'], {});
141145
}
142-
if (op['updateMany'].timestamps !== false) {
146+
if (doInitTimestamps) {
143147
applyTimestampsToChildren(now, op['updateMany']['update'], model.schema);
144148
}
145149

@@ -184,7 +188,7 @@ module.exports = function castBulkWrite(originalModel, op, options) {
184188

185189
// set `skipId`, otherwise we get "_id field cannot be changed"
186190
const doc = new model(op['replaceOne']['replacement'], strict, true);
187-
if (model.schema.options.timestamps) {
191+
if (model.schema.options.timestamps && getTimestampsOpt(op['replaceOne'], options)) {
188192
doc.initializeTimestamps();
189193
}
190194
if (options.session != null) {
@@ -273,3 +277,20 @@ function decideModelByObject(model, object) {
273277
}
274278
return model;
275279
}
280+
281+
282+
/**
283+
* gets timestamps option for a given operation. If the option is set within an individual operation, use it. Otherwise, use the global timestamps option configured in the `bulkWrite` options. Overall default is `true`.
284+
* @api private
285+
*/
286+
287+
function getTimestampsOpt(opCommand, options) {
288+
const opLevelOpt = opCommand.timestamps;
289+
const bulkLevelOpt = options.timestamps;
290+
if (opLevelOpt != null) {
291+
return opLevelOpt;
292+
} else if (bulkLevelOpt != null) {
293+
return bulkLevelOpt;
294+
}
295+
return true;
296+
}

lib/model.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3467,6 +3467,7 @@ function _setIsNew(doc, val) {
34673467
*
34683468
* @param {Array} ops
34693469
* @param {Object} [ops.insertOne.document] The document to insert
3470+
* @param {Object} [ops.insertOne.timestamps=true] If false, do not apply [timestamps](https://mongoosejs.com/docs/guide.html#timestamps) to the operation
34703471
* @param {Object} [ops.updateOne.filter] Update the first document that matches this filter
34713472
* @param {Object} [ops.updateOne.update] An object containing [update operators](https://www.mongodb.com/docs/manual/reference/operator/update/)
34723473
* @param {Boolean} [ops.updateOne.upsert=false] If true, insert a doc if none match
@@ -3484,8 +3485,10 @@ function _setIsNew(doc, val) {
34843485
* @param {Object} [ops.replaceOne.filter] Replace the first document that matches this filter
34853486
* @param {Object} [ops.replaceOne.replacement] The replacement document
34863487
* @param {Boolean} [ops.replaceOne.upsert=false] If true, insert a doc if no documents match `filter`
3488+
* @param {Object} [ops.replaceOne.timestamps=true] If false, do not apply [timestamps](https://mongoosejs.com/docs/guide.html#timestamps) to the operation
34873489
* @param {Object} [options]
34883490
* @param {Boolean} [options.ordered=true] If true, execute writes in order and stop at the first error. If false, execute writes in parallel and continue until all writes have either succeeded or errored.
3491+
* @param {Boolean} [options.timestamps=true] If false, do not apply [timestamps](https://mongoosejs.com/docs/guide.html#timestamps) to any operations. Can be overridden at the operation-level.
34893492
* @param {ClientSession} [options.session=null] The session associated with this bulk write. See [transactions docs](https://mongoosejs.com/docs/transactions.html).
34903493
* @param {String|number} [options.w=1] The [write concern](https://www.mongodb.com/docs/manual/reference/write-concern/). See [`Query#w()`](https://mongoosejs.com/docs/api/query.html#Query.prototype.w()) for more information.
34913494
* @param {number} [options.wtimeout=null] The [write concern timeout](https://www.mongodb.com/docs/manual/reference/write-concern/#wtimeout).

types/models.d.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ declare module 'mongoose' {
2828
skipValidation?: boolean;
2929
throwOnValidationError?: boolean;
3030
strict?: boolean | 'throw';
31+
/** When false, do not add timestamps to documents. Can be overridden at the operation level. */
32+
timestamps?: boolean;
3133
}
3234

3335
interface MongooseBulkSaveOptions extends mongodb.BulkWriteOptions {
@@ -179,7 +181,9 @@ declare module 'mongoose' {
179181
};
180182

181183
export interface InsertOneModel<TSchema> {
182-
document: mongodb.OptionalId<TSchema>
184+
document: mongodb.OptionalId<TSchema>;
185+
/** When false, do not add timestamps. When true, overrides the `timestamps` option set in the `bulkWrite` options. */
186+
timestamps?: boolean;
183187
}
184188

185189
export interface ReplaceOneModel<TSchema = AnyObject> {
@@ -193,6 +197,8 @@ declare module 'mongoose' {
193197
hint?: mongodb.Hint;
194198
/** When true, creates a new document if no document matches the query. */
195199
upsert?: boolean;
200+
/** When false, do not add timestamps. When true, overrides the `timestamps` option set in the `bulkWrite` options. */
201+
timestamps?: boolean;
196202
}
197203

198204
export interface UpdateOneModel<TSchema = AnyObject> {
@@ -208,7 +214,7 @@ declare module 'mongoose' {
208214
hint?: mongodb.Hint;
209215
/** When true, creates a new document if no document matches the query. */
210216
upsert?: boolean;
211-
/** When false, do not add timestamps. */
217+
/** When false, do not add timestamps. When true, overrides the `timestamps` option set in the `bulkWrite` options. */
212218
timestamps?: boolean;
213219
}
214220

@@ -225,7 +231,7 @@ declare module 'mongoose' {
225231
hint?: mongodb.Hint;
226232
/** When true, creates a new document if no document matches the query. */
227233
upsert?: boolean;
228-
/** When false, do not add timestamps. */
234+
/** When false, do not add timestamps. When true, overrides the `timestamps` option set in the `bulkWrite` options. */
229235
timestamps?: boolean;
230236
}
231237

0 commit comments

Comments
 (0)