Skip to content

Commit a86bd24

Browse files
committed
Merge branch 'master' into gh-pages
2 parents 0ca3ef7 + b34aba6 commit a86bd24

14 files changed

+159
-20
lines changed

.github/workflows/benchmark.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ jobs:
2828
- name: Setup node
2929
uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
3030
with:
31-
node-version: 16
31+
node-version: 22
3232

3333
- run: npm install
3434

.github/workflows/documentation.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ jobs:
3333
- name: Setup node
3434
uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
3535
with:
36-
node-version: 20
36+
node-version: 22
3737

3838
- run: npm install
3939

@@ -54,7 +54,7 @@ jobs:
5454
- name: Setup node
5555
uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
5656
with:
57-
node-version: 20
57+
node-version: 22
5858

5959
- run: npm install
6060
- name: Setup MongoDB

.github/workflows/test.yml

+4-4
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ jobs:
2727
- name: Setup node
2828
uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
2929
with:
30-
node-version: 18
30+
node-version: 22
3131

3232
- run: npm install
3333

@@ -39,7 +39,7 @@ jobs:
3939
strategy:
4040
fail-fast: false
4141
matrix:
42-
node: [16, 18, 20]
42+
node: [16, 18, 20, 22]
4343
os: [ubuntu-20.04, ubuntu-22.04]
4444
mongodb: [4.4.29, 5.0.26, 6.0.15, 7.0.12, 8.0.0]
4545
include:
@@ -98,7 +98,7 @@ jobs:
9898
- name: Setup node
9999
uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
100100
with:
101-
node-version: 16
101+
node-version: 22
102102
- name: Load MongoDB binary cache
103103
id: cache-mongodb-binaries
104104
uses: actions/cache@v4
@@ -126,7 +126,7 @@ jobs:
126126
- name: Setup node
127127
uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
128128
with:
129-
node-version: 16
129+
node-version: 22
130130
- run: npm install
131131
- name: Test
132132
run: npm run test-rs

.github/workflows/tidelift-alignment.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ jobs:
1919
- name: Setup node
2020
uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
2121
with:
22-
node-version: 16
22+
node-version: 22
2323
- name: Alignment
2424
uses: tidelift/alignment-action@8d7700fe795fc01179c1f9fa05b72a089873027d # main
2525
env:

.github/workflows/tsd.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ jobs:
2525
- name: Setup node
2626
uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
2727
with:
28-
node-version: 18
28+
node-version: 22
2929

3030
- run: npm install
3131

@@ -43,7 +43,7 @@ jobs:
4343
- name: Setup node
4444
uses: actions/setup-node@39370e3970a6d050c480ffad4ff0ed4d3fdee5af # v4.1.0
4545
with:
46-
node-version: 16
46+
node-version: 22
4747

4848
- run: npm install
4949

CHANGELOG.md

+14
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,17 @@
1+
8.8.2 / 2024-11-18
2+
==================
3+
* fix(model): handle array filters when casting bulkWrite #15036 #14978
4+
* fix(model): make diffIndexes() avoid trying to drop default timeseries collection index #15035 #14984
5+
* fix: save execution stack in query as string #15039 [durran](https://github.com/durran)
6+
* types(cursor): correct asyncIterator and asyncDispose for TypeScript with lib: 'esnext' #15038
7+
* docs(migrating_to_8): add note about removing findByIdAndRemove #15024 [dragontaek-lee](https://github.com/dragontaek-lee)
8+
9+
8.8.1 / 2024-11-08
10+
==================
11+
* perf: make a few micro-optimizations to help speed up findOne() #15022 #14906
12+
* fix: apply embedded discriminators to subdoc schemas before compiling top level model so middleware applies correctly #15001 #14961
13+
* fix(query): add overwriteImmutable option to allow updating immutable properties without disabling strict mode #15000 #8619
14+
115
8.8.0 / 2024-10-31
216
==================
317
* feat: upgrade mongodb -> ~6.10 #14991 #14877

docs/migrating_to_8.md

+3
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,9 @@ In Mongoose 7, `findOneAndRemove()` was an alias for `findOneAndDelete()` that M
8787
Mongoose 8 no longer supports `findOneAndRemove()`.
8888
Use `findOneAndDelete()` instead.
8989

90+
Similarly, Mongoose 8 no longer supports `findByIdAndRemove()`, which was an alias for `findByIdAndDelete()`.
91+
Please use `findByIdAndDelete()` instead.
92+
9093
## Removed `count()` {#removed-count}
9194

9295
`Model.count()` and `Query.prototype.count()` were removed in Mongoose 8. Use `Model.countDocuments()` and `Query.prototype.countDocuments()` instead.
+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
'use strict';
2+
3+
/**
4+
* Returns `true` if the given index matches the schema's `timestamps` options
5+
*/
6+
7+
module.exports = function isTimeseriesIndex(dbIndex, schemaOptions) {
8+
if (schemaOptions.timeseries == null) {
9+
return false;
10+
}
11+
const { timeField, metaField } = schemaOptions.timeseries;
12+
if (typeof timeField !== 'string' || typeof metaField !== 'string') {
13+
return false;
14+
}
15+
return Object.keys(dbIndex.key).length === 2 && dbIndex.key[timeField] === 1 && dbIndex.key[metaField] === 1;
16+
};

lib/helpers/model/castBulkWrite.js

+4-2
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,8 @@ module.exports = function castBulkWrite(originalModel, op, options) {
103103
});
104104
op['updateOne']['update'] = castUpdate(model.schema, update, {
105105
strict: strict,
106-
upsert: op['updateOne'].upsert
106+
upsert: op['updateOne'].upsert,
107+
arrayFilters: op['updateOne'].arrayFilters
107108
}, model, op['updateOne']['filter']);
108109
} catch (error) {
109110
return callback(error, null);
@@ -162,7 +163,8 @@ module.exports = function castBulkWrite(originalModel, op, options) {
162163

163164
op['updateMany']['update'] = castUpdate(model.schema, op['updateMany']['update'], {
164165
strict: strict,
165-
upsert: op['updateMany'].upsert
166+
upsert: op['updateMany'].upsert,
167+
arrayFilters: op['updateMany'].arrayFilters
166168
}, model, op['updateMany']['filter']);
167169
} catch (error) {
168170
return callback(error, null);

lib/model.js

+9-2
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ const immediate = require('./helpers/immediate');
5151
const internalToObjectOptions = require('./options').internalToObjectOptions;
5252
const isDefaultIdIndex = require('./helpers/indexes/isDefaultIdIndex');
5353
const isIndexEqual = require('./helpers/indexes/isIndexEqual');
54+
const isTimeseriesIndex = require('./helpers/indexes/isTimeseriesIndex');
5455
const {
5556
getRelatedDBIndexes,
5657
getRelatedSchemaIndexes
@@ -1418,6 +1419,10 @@ function getIndexesToDrop(schema, schemaIndexes, dbIndexes) {
14181419
if (isDefaultIdIndex(dbIndex)) {
14191420
continue;
14201421
}
1422+
// Timeseries collections have a default index on { timeField: 1, metaField: 1 }.
1423+
if (isTimeseriesIndex(dbIndex, schema.options)) {
1424+
continue;
1425+
}
14211426

14221427
for (const [schemaIndexKeysObject, schemaIndexOptions] of schemaIndexes) {
14231428
const options = decorateDiscriminatorIndexOptions(schema, clone(schemaIndexOptions));
@@ -1429,9 +1434,11 @@ function getIndexesToDrop(schema, schemaIndexes, dbIndexes) {
14291434
}
14301435
}
14311436

1432-
if (!found) {
1433-
toDrop.push(dbIndex.name);
1437+
if (found) {
1438+
continue;
14341439
}
1440+
1441+
toDrop.push(dbIndex.name);
14351442
}
14361443

14371444
return toDrop;

lib/query.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -4433,10 +4433,10 @@ Query.prototype.exec = async function exec(op) {
44334433
str = str.slice(0, 60) + '...';
44344434
}
44354435
const err = new MongooseError('Query was already executed: ' + str);
4436-
err.originalStack = this._executionStack.stack;
4436+
err.originalStack = this._executionStack;
44374437
throw err;
44384438
} else {
4439-
this._executionStack = new Error();
4439+
this._executionStack = new Error().stack;
44404440
}
44414441

44424442
let skipWrappedFunction = null;

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "mongoose",
33
"description": "Mongoose MongoDB ODM",
4-
"version": "8.8.0",
4+
"version": "8.8.2",
55
"author": "Guillermo Rauch <[email protected]>",
66
"keywords": [
77
"mongodb",

test/model.test.js

+95
Original file line numberDiff line numberDiff line change
@@ -4125,6 +4125,55 @@ describe('Model', function() {
41254125
assert.equal(err.validationErrors[0].errors['num'].name, 'CastError');
41264126
});
41274127

4128+
it('handles array filters (gh-14978)', async function() {
4129+
const embedDiscriminatorSchema = new mongoose.Schema({
4130+
field1: String
4131+
});
4132+
4133+
const embedSchema = new mongoose.Schema({
4134+
field: String,
4135+
key: String
4136+
}, { discriminatorKey: 'key' });
4137+
embedSchema.discriminator('Type1', embedDiscriminatorSchema);
4138+
4139+
const testSchema = new mongoose.Schema({
4140+
testArray: [embedSchema]
4141+
});
4142+
const TestModel = db.model('Test', testSchema);
4143+
4144+
const test = new TestModel({
4145+
testArray: [{
4146+
key: 'Type1',
4147+
field: 'field',
4148+
field1: 'field1'
4149+
}]
4150+
});
4151+
const r1 = await test.save();
4152+
assert.equal(r1.testArray[0].field1, 'field1');
4153+
4154+
const field1update = 'field1 update';
4155+
await TestModel.bulkWrite([{
4156+
updateOne: {
4157+
filter: { _id: r1._id },
4158+
update: {
4159+
$set: {
4160+
'testArray.$[element].field1': field1update,
4161+
'testArray.$[element].nonexistentProp': field1update
4162+
}
4163+
},
4164+
arrayFilters: [
4165+
{
4166+
'element._id': r1.testArray[0]._id,
4167+
'element.key': 'Type1'
4168+
}
4169+
]
4170+
}
4171+
}]);
4172+
const r2 = await TestModel.findById(r1._id).lean();
4173+
assert.equal(r2.testArray[0].field1, field1update);
4174+
assert.strictEqual(r2.testArray[0].nonexistentProp, undefined);
4175+
});
4176+
41284177
it('with child timestamps and array filters (gh-7032)', async function() {
41294178
const childSchema = new Schema({ name: String }, { timestamps: true });
41304179

@@ -8147,6 +8196,52 @@ describe('Model', function() {
81478196
assert.ok(obj.post.updatedAt.valueOf(), new Date('2023-06-01T18:00:00.000Z').valueOf());
81488197
});
81498198
});
8199+
8200+
describe('diffIndexes()', function() {
8201+
it('avoids trying to drop timeseries collections (gh-14984)', async function() {
8202+
const version = await start.mongodVersion();
8203+
if (version[0] < 5) {
8204+
this.skip();
8205+
return;
8206+
}
8207+
8208+
const schema = new mongoose.Schema(
8209+
{
8210+
time: {
8211+
type: Date
8212+
},
8213+
deviceId: {
8214+
type: String
8215+
}
8216+
},
8217+
{
8218+
timeseries: {
8219+
timeField: 'time',
8220+
metaField: 'deviceId',
8221+
granularity: 'seconds'
8222+
},
8223+
autoCreate: false
8224+
}
8225+
);
8226+
8227+
const TestModel = db.model(
8228+
'TimeSeriesTest',
8229+
schema,
8230+
'gh14984'
8231+
);
8232+
8233+
await db.dropCollection('gh14984').catch(err => {
8234+
if (err.codeName === 'NamespaceNotFound') {
8235+
return;
8236+
}
8237+
throw err;
8238+
});
8239+
await TestModel.createCollection();
8240+
8241+
const { toDrop } = await TestModel.diffIndexes();
8242+
assert.deepStrictEqual(toDrop, []);
8243+
});
8244+
});
81508245
});
81518246

81528247

types/cursor.d.ts

+5-3
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@ declare module 'mongoose' {
1111
signal?: AbortSignal;
1212
}
1313

14-
class Cursor<DocType = any, Options = never> extends stream.Readable {
15-
[Symbol.asyncIterator](): AsyncIterableIterator<DocType>;
14+
class Cursor<DocType = any, Options = never, NextResultType = DocType | null> extends stream.Readable {
15+
[Symbol.asyncIterator](): Cursor<IteratorResult<DocType>, Options, IteratorResult<DocType>>;
16+
17+
[Symbol.asyncDispose](): Promise<void>;
1618

1719
/**
1820
* Adds a [cursor flag](https://mongodb.github.io/node-mongodb-native/4.9/classes/FindCursor.html#addCursorFlag).
@@ -58,7 +60,7 @@ declare module 'mongoose' {
5860
* Get the next document from this cursor. Will return `null` when there are
5961
* no documents left.
6062
*/
61-
next(): Promise<DocType | null>;
63+
next(): Promise<NextResultType>;
6264

6365
options: Options;
6466
}

0 commit comments

Comments
 (0)