From 26f9af4edb975d1e513ea781f6e07d8aa25bf6a1 Mon Sep 17 00:00:00 2001 From: hasezoey Date: Thu, 6 Oct 2022 09:41:23 +0200 Subject: [PATCH 01/10] chore(template::bug): add field for typescript version --- .github/ISSUE_TEMPLATE/bug.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml index 3089b69e90e..98132d430e4 100644 --- a/.github/ISSUE_TEMPLATE/bug.yml +++ b/.github/ISSUE_TEMPLATE/bug.yml @@ -37,6 +37,14 @@ body: validations: required: true + - type: input + id: typescript-version + attributes: + label: Typescript version + placeholder: 4.8.x + validations: + required: false + - type: textarea id: description attributes: From 2a4d2e0915890a8f79448a3645760de0e3217fe5 Mon Sep 17 00:00:00 2001 From: Fabio Cingottini Date: Thu, 6 Oct 2022 14:48:37 +0200 Subject: [PATCH 02/10] fix(types): add missing densify type pipeline type densify pipeline stage was not in the union type for PipelineStage, this was causing ts error when users where trying to call aggregate method with densify stage --- types/pipelinestage.d.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/types/pipelinestage.d.ts b/types/pipelinestage.d.ts index 9086a4afb30..5d3c4023f0d 100644 --- a/types/pipelinestage.d.ts +++ b/types/pipelinestage.d.ts @@ -8,6 +8,7 @@ declare module 'mongoose' { | PipelineStage.BucketAuto | PipelineStage.CollStats | PipelineStage.Count + | PipelineStage.Densify | PipelineStage.Facet | PipelineStage.GeoNear | PipelineStage.GraphLookup From 5555919eef83dc3683c667456965f9f44c6ac727 Mon Sep 17 00:00:00 2001 From: Fabio Cingottini Date: Thu, 6 Oct 2022 18:05:19 +0200 Subject: [PATCH 03/10] fix(types): adjust replaceWith type pipeline stage replaceWith pipeline stage was not accepting a field as a parameter. This was causing ts error when users where trying to call aggregate method with replaceWith stage in unusual ways --- types/pipelinestage.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/pipelinestage.d.ts b/types/pipelinestage.d.ts index 5d3c4023f0d..bbc98324a75 100644 --- a/types/pipelinestage.d.ts +++ b/types/pipelinestage.d.ts @@ -202,7 +202,7 @@ declare module 'mongoose' { export interface ReplaceWith { /** [`$replaceWith` reference](https://docs.mongodb.com/manual/reference/operator/aggregation/replaceWith/) */ - $replaceWith: ObjectExpressionOperator; + $replaceWith: ObjectExpressionOperator | { [field: string]: Expression }; } export interface Sample { From 49a46f891cf6bc61aaef72430e04beeb00c62639 Mon Sep 17 00:00:00 2001 From: hasezoey Date: Fri, 7 Oct 2022 10:01:59 +0200 Subject: [PATCH 04/10] docs(guide): update broken read-preference links fixes #12525 --- docs/guide.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/guide.md b/docs/guide.md index 54651a6ed35..454dac270cf 100644 --- a/docs/guide.md +++ b/docs/guide.md @@ -744,9 +744,9 @@ The read option also allows us to specify _tag sets_. These tell the [driver](https://github.com/mongodb/node-mongodb-native/) from which members of the replica-set it should attempt to read. Read more about tag sets [here](http://docs.mongodb.org/manual/applications/replication/#tag-sets) and -[here](http://mongodb.github.com/node-mongodb-native/driver-articles/anintroductionto1_1and2_2.html#read-preferences). +[here](https://www.mongodb.com/docs/manual/core/read-preference). -_NOTE: you may also specify the driver read pref [strategy](http://mongodb.github.com/node-mongodb-native/api-generated/replset.html?highlight=strategy) +_NOTE: you may also specify the driver read preference [strategy](https://www.mongodb.com/docs/manual/core/read-preference/#read-preference-modes) option when connecting:_ ```javascript From 93345d9a68f8f402f6ec3056ef3584fb630a0c61 Mon Sep 17 00:00:00 2001 From: Luca Pizzini Date: Sat, 8 Oct 2022 12:47:51 +0200 Subject: [PATCH 05/10] docs(connection): improved useDb() documentation addresses #11187 --- lib/connection.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/connection.js b/lib/connection.js index ccf14825d18..482a0c2718e 100644 --- a/lib/connection.js +++ b/lib/connection.js @@ -1533,6 +1533,15 @@ Connection.prototype.syncIndexes = async function syncIndexes(options = {}) { * Switches to a different database using the same connection pool. * * Returns a new connection object, with the new db. + * + * #### Example: + * + * const conn = mongoose.createConnection('mongodb://localhost:27017'); + * + * // Creates an un-cached connection to `mydb`  + * const db = conn.useDb('mydb'); + * // Creates a cached connection to `mydb2` + * const db2 = conn.useDb('mydb2', { useChache: true }); * * @method useDb * @memberOf Connection From fa86ae1445be74763b350f70a837f1dba8f80538 Mon Sep 17 00:00:00 2001 From: Luca Pizzini Date: Sat, 8 Oct 2022 12:50:27 +0200 Subject: [PATCH 06/10] fix lint --- lib/connection.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/connection.js b/lib/connection.js index 482a0c2718e..9d7f121357e 100644 --- a/lib/connection.js +++ b/lib/connection.js @@ -1533,12 +1533,12 @@ Connection.prototype.syncIndexes = async function syncIndexes(options = {}) { * Switches to a different database using the same connection pool. * * Returns a new connection object, with the new db. - * + * * #### Example: - * + * * const conn = mongoose.createConnection('mongodb://localhost:27017'); - * - * // Creates an un-cached connection to `mydb`  + * + * // Creates an un-cached connection to `mydb` * const db = conn.useDb('mydb'); * // Creates a cached connection to `mydb2` * const db2 = conn.useDb('mydb2', { useChache: true }); From 06ab5b84723b8ec3d40b1c02d2f24e7c27ae0de9 Mon Sep 17 00:00:00 2001 From: Hafez Date: Sat, 8 Oct 2022 15:20:39 +0200 Subject: [PATCH 07/10] Update lib/connection.js --- lib/connection.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/connection.js b/lib/connection.js index 9d7f121357e..d05bc902706 100644 --- a/lib/connection.js +++ b/lib/connection.js @@ -1541,7 +1541,7 @@ Connection.prototype.syncIndexes = async function syncIndexes(options = {}) { * // Creates an un-cached connection to `mydb` * const db = conn.useDb('mydb'); * // Creates a cached connection to `mydb2` - * const db2 = conn.useDb('mydb2', { useChache: true }); + * const db2 = conn.useDb('mydb2', { useCache: true }); * * @method useDb * @memberOf Connection From 24d01d486e188971dc4438096e5a996e6c80b6d8 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Sat, 8 Oct 2022 12:19:56 -0400 Subject: [PATCH 08/10] Update connection.js --- lib/connection.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/connection.js b/lib/connection.js index d05bc902706..98fb871c115 100644 --- a/lib/connection.js +++ b/lib/connection.js @@ -1536,11 +1536,13 @@ Connection.prototype.syncIndexes = async function syncIndexes(options = {}) { * * #### Example: * - * const conn = mongoose.createConnection('mongodb://localhost:27017'); + * // Connect to `initialdb` first + * const conn = await mongoose.createConnection('mongodb://localhost:27017/initialdb').asPromise(); * * // Creates an un-cached connection to `mydb` * const db = conn.useDb('mydb'); - * // Creates a cached connection to `mydb2` + * // Creates a cached connection to `mydb2`. All calls to `conn.useDb('mydb2', { useCache: true })` will return the same + * // connection instance as opposed to creating a new connection instance * const db2 = conn.useDb('mydb2', { useCache: true }); * * @method useDb From e6207ee7d3e1900bc16c05d06b18c9b03d29dd17 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Sat, 8 Oct 2022 20:58:18 -0400 Subject: [PATCH 09/10] Update bug.yml --- .github/ISSUE_TEMPLATE/bug.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml index 98132d430e4..804597275f7 100644 --- a/.github/ISSUE_TEMPLATE/bug.yml +++ b/.github/ISSUE_TEMPLATE/bug.yml @@ -40,7 +40,7 @@ body: - type: input id: typescript-version attributes: - label: Typescript version + label: Typescript version (if applicable) placeholder: 4.8.x validations: required: false From 76eaadd13d11bb140b911fba9103756ce5950a80 Mon Sep 17 00:00:00 2001 From: Raphael Papazikas Date: Wed, 12 Oct 2022 01:58:54 +0200 Subject: [PATCH 10/10] add $fill pipeline stage gh-12536: add tests revert some remove operators enhance type fix example --- lib/aggregate.js | 36 +++++++++++---- test/aggregate.test.js | 19 ++++++++ test/types/PipelineStage.test.ts | 79 ++++++++++++++++++++++++++++++++ types/aggregate.d.ts | 3 ++ types/expressions.d.ts | 22 +++++++++ types/pipelinestage.d.ts | 11 +++++ 6 files changed, 162 insertions(+), 8 deletions(-) diff --git a/lib/aggregate.js b/lib/aggregate.js index 2426a256ca1..7178cce7526 100644 --- a/lib/aggregate.js +++ b/lib/aggregate.js @@ -111,11 +111,11 @@ Aggregate.prototype.model = function(model) { this._model = model; if (model.schema != null) { if (this.options.readPreference == null && - model.schema.options.read != null) { + model.schema.options.read != null) { this.options.readPreference = model.schema.options.read; } if (this.options.collation == null && - model.schema.options.collation != null) { + model.schema.options.collation != null) { this.options.collation = model.schema.options.collation; } } @@ -158,7 +158,7 @@ Aggregate.prototype.append = function() { * Requires MongoDB v3.4+ to work * * #### Example: - * + * * // adding new fields based on existing fields * aggregate.addFields({ * newField: '$b.nested' @@ -328,6 +328,28 @@ Aggregate.prototype.project = function(arg) { * @api public */ +/** + * Appends a new $fill operator to this aggregate pipeline. + * + * #### Example: + * + * aggregate.fill({ + * output: { + * bootsSold: { value: 0 }, + * sandalsSold: { value: 0 }, + * sneakersSold: { value: 0 } + * } + * }); + * + * @see $fill https://www.mongodb.com/docs/manual/reference/operator/aggregation/fill/ + * @method fill + * @memberOf Aggregate + * @instance + * @param {Object} arg $fill operator contents + * @return {Aggregate} + * @api public + */ + /** * Appends a new $geoNear operator to this aggregate pipeline. * @@ -366,7 +388,7 @@ Aggregate.prototype.near = function(arg) { * define methods */ -'group match skip limit out densify'.split(' ').forEach(function($operator) { +'group match skip limit out densify fill'.split(' ').forEach(function($operator) { Aggregate.prototype[$operator] = function(arg) { const op = {}; op['$' + $operator] = arg; @@ -702,7 +724,7 @@ Aggregate.prototype.readConcern = function(level) { Aggregate.prototype.redact = function(expression, thenExpr, elseExpr) { if (arguments.length === 3) { if ((typeof thenExpr === 'string' && !validRedactStringValues.has(thenExpr)) || - (typeof elseExpr === 'string' && !validRedactStringValues.has(elseExpr))) { + (typeof elseExpr === 'string' && !validRedactStringValues.has(elseExpr))) { throw new Error('If thenExpr or elseExpr is string, it must be either $$DESCEND, $$PRUNE or $$KEEP'); } @@ -1099,9 +1121,7 @@ Aggregate.prototype.catch = function(reject) { if (Symbol.asyncIterator != null) { Aggregate.prototype[Symbol.asyncIterator] = function() { - return this.cursor({ useMongooseAggCursor: true }). - transformNull(). - _transformForAsyncIterator(); + return this.cursor({ useMongooseAggCursor: true }).transformNull()._transformForAsyncIterator(); }; } diff --git a/test/aggregate.test.js b/test/aggregate.test.js index 168db7a7e34..91acbf8716e 100644 --- a/test/aggregate.test.js +++ b/test/aggregate.test.js @@ -389,6 +389,25 @@ describe('aggregate: ', function() { }); }); + describe('fill', function() { + it('works', function() { + const aggregate = new Aggregate(); + const obj = { + output: + { + bootsSold: { value: 0 }, + sandalsSold: { value: 0 }, + sneakersSold: { value: 0 } + } + }; + + aggregate.fill(obj); + + assert.equal(aggregate._pipeline.length, 1); + assert.deepEqual(aggregate._pipeline[0].$fill, obj); + }); + }); + describe('model()', function() { it('works', function() { const aggregate = new Aggregate(); diff --git a/test/types/PipelineStage.test.ts b/test/types/PipelineStage.test.ts index 29c4696caca..28670945721 100644 --- a/test/types/PipelineStage.test.ts +++ b/test/types/PipelineStage.test.ts @@ -311,6 +311,85 @@ const setWindowFields4: PipelineStage = { } }; +const setWindowFieldsLinearFill: PipelineStage = { + $setWindowFields: { + partitionBy: '$stock', + sortBy: { date: 1 }, + output: { + price: { $linearFill: '$price' } + } + } +}; + +const setWindowFieldsLocf: PipelineStage = { + $setWindowFields: { + partitionBy: '$stock', + sortBy: { date: 1 }, + output: { + price: { $locf: '$price' } + } + } +}; + +const fillWithOutput: PipelineStage = { + $fill: { + output: { + bootsSold: { value: 0 } + } + } +}; + +const fillWithPartitionBy: PipelineStage = { + $fill: { + partitionBy: 'date', + output: { + bootsSold: { value: 0 } + } + } +}; + +const fillWithPartitionByFields: PipelineStage = { + $fill: { + partitionByFields: ['date'], + output: { + bootsSold: { value: 0 } + } + } +}; + +const fillWithSortBy: PipelineStage = { + $fill: { + sortBy: { + date: -1 + }, + output: { + bootsSold: { value: 0 } + } + } +}; + +const fillWithOutputMethodLinear: PipelineStage = { + $fill: { + sortBy: { + date: -1 + }, + output: { + bootsSold: { method: 'linear' } + } + } +}; + +const fillWithOutputMethodLocf: PipelineStage = { + $fill: { + sortBy: { + date: -1 + }, + output: { + bootsSold: { method: 'locf' } + } + } +}; + const group1: PipelineStage = { $group: { _id: null, ageStdDev: { $stdDevSamp: '$age' } } }; const group2: PipelineStage = { $group: { diff --git a/types/aggregate.d.ts b/types/aggregate.d.ts index df5b4efdcc6..5352e22d0f6 100644 --- a/types/aggregate.d.ts +++ b/types/aggregate.d.ts @@ -133,6 +133,9 @@ declare module 'mongoose' { /** Combines multiple aggregation pipelines. */ facet(options: PipelineStage.Facet['$facet']): this; + /** Appends a new $fill operator to this aggregate pipeline */ + fill(arg: PipelineStage.Fill['$fill']): this; + /** Appends new custom $graphLookup operator(s) to this aggregate pipeline, performing a recursive search on a collection. */ graphLookup(options: PipelineStage.GraphLookup['$graphLookup']): this; diff --git a/types/expressions.d.ts b/types/expressions.d.ts index c2d83ed87dd..cf48bef8538 100644 --- a/types/expressions.d.ts +++ b/types/expressions.d.ts @@ -1180,6 +1180,26 @@ declare module 'mongoose' { $last: Expression; } + export interface LinearFill { + /** + * Fills null and missing fields in a window using linear interpolation based on surrounding field values. + * + * @version 5.3 + * @see https://www.mongodb.com/docs/manual/reference/operator/aggregation/linearFill + */ + $linearFill: Expression + } + + export interface Locf { + /** + * Last observation carried forward. Sets values for null and missing fields in a window to the last non-null value for the field. + * + * @version 5.2 + * @see https://www.mongodb.com/docs/manual/reference/operator/aggregation/locf + */ + $locf: Expression + } + export interface Map { /** * Applies a subexpression to each element of an array and returns the array of resulting values in order. Accepts named parameters. @@ -2735,6 +2755,8 @@ declare module 'mongoose' { Expression.First | Expression.Integral | Expression.Last | + Expression.LinearFill | + Expression.Locf | Expression.Max | Expression.Min | Expression.Push | diff --git a/types/pipelinestage.d.ts b/types/pipelinestage.d.ts index bbc98324a75..f58e4b61f27 100644 --- a/types/pipelinestage.d.ts +++ b/types/pipelinestage.d.ts @@ -10,6 +10,7 @@ declare module 'mongoose' { | PipelineStage.Count | PipelineStage.Densify | PipelineStage.Facet + | PipelineStage.Fill | PipelineStage.GeoNear | PipelineStage.GraphLookup | PipelineStage.Group @@ -90,6 +91,16 @@ declare module 'mongoose' { } } + export interface Fill { + /** [`$fill` reference](https://docs.mongodb.com/manual/reference/operator/aggregation/fill/) */ + $fill: { + partitionBy?: Expression, + partitionByFields?: string[], + sortBy?: Record, + output: Record + } + } + export interface Facet { /** [`$facet` reference](https://docs.mongodb.com/manual/reference/operator/aggregation/facet/) */ $facet: Record;