From 8d9baf7ed75294b2cad90ea56f245bfbceeec3de Mon Sep 17 00:00:00 2001 From: Syed Sadiq Ali <69423208+SadiqOnGithub@users.noreply.github.com> Date: Wed, 30 Nov 2022 21:03:36 +0530 Subject: [PATCH 01/23] Not Working: Throwing error with "localhost:27017" by using -- mongoose.connect('mongodb://localhost:27017/test') -- by node application, running on windows, is throwing this error : MongooseServerSelectionError: connect ECONNREFUSED ::1:27017 at Connection.openUri (C:\Users\lenovo\Documents\webistes projects\Node\node prac\mongo\node_modules\mongoose\lib\connection.js:824:32) at C:\Users\lenovo\Documents\webistes projects\Node\node prac\mongo\node_modules\mongoose\lib\index.js:412:10 at C:\Users\lenovo\Documents\webistes projects\Node\node prac\mongo\node_modules\mongoose\lib\helpers\promiseOrCallback.js:41:5 at new Promise () at promiseOrCallback (C:\Users\lenovo\Documents\webistes projects\Node\node prac\mongo\node_modules\mongoose\lib\helpers\promiseOrCallback.js:40:10) at Mongoose._promiseOrCallback (C:\Users\lenovo\Documents\webistes projects\Node\node prac\mongo\node_modules\mongoose\lib\index.js:1265:10) at Mongoose.connect (C:\Users\lenovo\Documents\webistes projects\Node\node prac\mongo\node_modules\mongoose\lib\index.js:411:20) at main (C:\Users\lenovo\Documents\webistes projects\Node\node prac\mongo\server.js:6:17) at Object. (C:\Users\lenovo\Documents\webistes projects\Node\node prac\mongo\server.js:3:1) at Module._compile (node:internal/modules/cjs/loader:1205:14) { reason: TopologyDescription { type: 'Unknown', servers: Map(1) { 'localhost:27017' => [ServerDescription] }, stale: false, compatible: true, heartbeatFrequencyMS: 10000, localThresholdMS: 15, setName: null, maxElectionId: null, maxSetVersion: null, commonWireVersion: 0, logicalSessionTimeoutMinutes: null }, code: undefined } ==================================X================================== I apologize if this proposed change is not up to the mark or is violating some community guidelines. but I wasted a lot of time on this so I can resist but propose this change. I think other people also have struggled with this read more on this stack overflow answer : https://stackoverflow.com/a/70517348/14075519 --- docs/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.md b/docs/index.md index 6d3a4da0b0e..505ab69f376 100644 --- a/docs/index.md +++ b/docs/index.md @@ -32,7 +32,7 @@ const mongoose = require('mongoose'); main().catch(err => console.log(err)); async function main() { - await mongoose.connect('mongodb://localhost:27017/test'); + await mongoose.connect('mongodb://127.0.0.1:27017/test'); // use `await mongoose.connect('mongodb://user:password@localhost:27017/test');` if your database has auth enabled } From 5c0cb113dc1514a2310d31434842cb41fc3d11de Mon Sep 17 00:00:00 2001 From: hasezoey Date: Tue, 6 Dec 2022 13:45:43 +0100 Subject: [PATCH 02/23] style(types/aggregate): rename generic to match Query definition makes it more clear what the generic is for --- types/aggregate.d.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/types/aggregate.d.ts b/types/aggregate.d.ts index 5352e22d0f6..7264a2f7db1 100644 --- a/types/aggregate.d.ts +++ b/types/aggregate.d.ts @@ -68,13 +68,13 @@ declare module 'mongoose' { [key: string]: any; } - class Aggregate implements SessionOperation { + class Aggregate implements SessionOperation { /** * Returns an asyncIterator for use with [`for/await/of` loops](https://thecodebarbarian.com/getting-started-with-async-iterators-in-node-js) * You do not need to call this function explicitly, the JavaScript runtime * will call it for you. */ - [Symbol.asyncIterator](): AsyncIterableIterator>; + [Symbol.asyncIterator](): AsyncIterableIterator>; options: AggregateOptions; @@ -103,7 +103,7 @@ declare module 'mongoose' { * resolved with either the doc(s) or rejected with the error. * Like [`.then()`](#query_Query-then), but only takes a rejection handler. */ - catch: Promise['catch']; + catch: Promise['catch']; /** Set the collation. */ collation(options: mongodb.CollationOptions): this; @@ -121,8 +121,8 @@ declare module 'mongoose' { /** Executes the aggregate pipeline on the currently bound Model. */ - exec(callback: Callback): void; - exec(): Promise; + exec(callback: Callback): void; + exec(): Promise; /** Execute the aggregation with explain */ explain(verbosity: mongodb.ExplainVerbosityLike, callback: Callback): void; @@ -215,7 +215,7 @@ declare module 'mongoose' { sort(arg: string | Record | PipelineStage.Sort['$sort']): this; /** Provides promise for aggregate. */ - then: Promise['then']; + then: Promise['then']; /** * Appends a new $sortByCount operator to this aggregate pipeline. Accepts either a string field name From d8b2c1e1cd0e1d2b503290271985b5692548ee64 Mon Sep 17 00:00:00 2001 From: Orgad Shaneh Date: Wed, 7 Dec 2022 09:58:49 +0200 Subject: [PATCH 03/23] Fix wrong circular dependency detection If the same object is referenced in multiple places, it was wrongfully detected as circular, even when it wasn't. Amends commit 7974f004fae549ac11bbc247ac371fe6be4aa137. Fixes #12775. --- lib/helpers/common.js | 1 + test/helpers/common.test.js | 7 +++++++ 2 files changed, 8 insertions(+) diff --git a/lib/helpers/common.js b/lib/helpers/common.js index fb3dbdd098a..ec7524da4c9 100644 --- a/lib/helpers/common.js +++ b/lib/helpers/common.js @@ -106,6 +106,7 @@ updatePath: '${recursion.raw.path}'`); modifiedPaths(val, path + key, result, recursion); } } + recursion.trace.delete(update); return result; } diff --git a/test/helpers/common.test.js b/test/helpers/common.test.js index 93dd982ae6b..4d82ea4ceef 100644 --- a/test/helpers/common.test.js +++ b/test/helpers/common.test.js @@ -14,4 +14,11 @@ describe('modifiedPaths, bad update value which has circular reference field', ( assert.throws(() => modifiedPaths(objA, 'path', null), /circular reference/); }); + + it('values with multiple references which are not circular should succeed', function() { + const objA = {}; + const objB = { a: objA, b: objA }; + + modifiedPaths(objB, 'path', null); + }); }); From 4be162ec5a896702b7791e02434ae1e925ef0990 Mon Sep 17 00:00:00 2001 From: Luca Pizzini Date: Wed, 7 Dec 2022 10:54:10 +0100 Subject: [PATCH 04/23] docs(query): updated explanation for slice fix #12474 --- lib/query.js | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/lib/query.js b/lib/query.js index d4ec9ab8cda..7a9b5f87ad1 100644 --- a/lib/query.js +++ b/lib/query.js @@ -370,17 +370,33 @@ Query.prototype.clone = function clone() { * * #### Example: * - * query.slice('comments', 5); - * query.slice('comments', -5); - * query.slice('comments', [10, 5]); - * query.where('comments').slice(5); - * query.where('comments').slice([-10, 5]); + * query.slice('comments', 5); // Returns the first 5 comments + * query.slice('comments', -5); // Returns the last 5 comments + * query.slice('comments', [10, 5]); // Returns the first 5 comments after the 10-th + * query.where('comments').slice(5); // Returns the first 5 comments + * query.where('comments').slice([-10, 5]); // Returns the first 5 comments after the 10-th to last + * + * **Note:** If the absolute value of the number of elements to be sliced is greater than the number of elements in the array, all array elements will be returned. + * + * // Given `arr`: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + * query.slice('arr', 20); // Returns [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + * query.slice('arr', -20); // Returns [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + * + * **Note:** If the number of elements to skip is positive and greater than the number of elements in the array, an empty array will be returned. + * + * // Given `arr`: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + * query.slice('arr', [20, 5]); // Returns [] + * + * **Note:** If the number of elements to skip is negative and its absolute value is greater than the number of elements in the array, the starting position is the start of the array. + * + * // Given `arr`: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] + * query.slice('arr', [-20, 5]); // Returns [1, 2, 3, 4, 5] * * @method slice * @memberOf Query * @instance * @param {String} [path] - * @param {Number} val number/range of elements to slice + * @param {Number|Array} val number of elements to slice or array with number of elements to skip and number of elements to slice * @return {Query} this * @see mongodb https://www.mongodb.org/display/DOCS/Retrieving+a+Subset+of+Fields#RetrievingaSubsetofFields-RetrievingaSubrangeofArrayElements * @see $slice https://docs.mongodb.org/manual/reference/projection/slice/#prj._S_slice From 75b7fddaf5c45d9ba31c35308fbee8cfce7787ae Mon Sep 17 00:00:00 2001 From: Danny Brudner Date: Wed, 7 Dec 2022 21:40:17 +0200 Subject: [PATCH 05/23] return value from super.delete() --- lib/types/map.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/types/map.js b/lib/types/map.js index 4c571160fb8..2004dd4ad3e 100644 --- a/lib/types/map.js +++ b/lib/types/map.js @@ -180,7 +180,7 @@ class MongooseMap extends Map { } this.set(key, undefined); - super.delete(key); + return super.delete(key); } /** From 6916fe6f3219eac6bbd44bb497ff508688e9cc6f Mon Sep 17 00:00:00 2001 From: Phillip Huang Date: Thu, 8 Dec 2022 21:12:28 -0800 Subject: [PATCH 06/23] InferSchemaType: consider { required: boolean } required if it isn't explicitly false --- types/inferschematype.d.ts | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/types/inferschematype.d.ts b/types/inferschematype.d.ts index e8aff0539fc..1b24d6daa32 100644 --- a/types/inferschematype.d.ts +++ b/types/inferschematype.d.ts @@ -83,15 +83,19 @@ type IsPathDefaultUndefined = PathType extends { default: undefined } type IsPathRequired = P extends { required: true | [true, string | undefined] } | ArrayConstructor | any[] ? true - : P extends (Record) - ? IsPathDefaultUndefined

extends true + : P extends { required: boolean } + ? P extends { required: false } ? false : true - : P extends (Record) - ? P extends { default: any } - ? IfEquals - : false - : false; + : P extends (Record) + ? IsPathDefaultUndefined

extends true + ? false + : true + : P extends (Record) + ? P extends { default: any } + ? IfEquals + : false + : false; /** * @summary Path base type defined by using TypeKey From f3dbd45642f87582f16dbf685133c1fdf8f1ae03 Mon Sep 17 00:00:00 2001 From: Luca Pizzini Date: Fri, 9 Dec 2022 09:18:23 +0100 Subject: [PATCH 07/23] fix(model): prevent index creation on syncIndexes if not necessary MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fix #12250 --- lib/model.js | 15 ++++++++++++--- test/model.test.js | 7 ++++--- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/lib/model.js b/lib/model.js index 382e0af2d09..51d33bf5a41 100644 --- a/lib/model.js +++ b/lib/model.js @@ -1570,14 +1570,14 @@ Model.diffIndexes = function diffIndexes(options, callback) { const schemaIndexes = getRelatedSchemaIndexes(model, schema.indexes()); const toDrop = getIndexesToDrop(schema, schemaIndexes, dbIndexes); - const toCreate = getIndexesToCreate(schema, schemaIndexes, dbIndexes); + const toCreate = getIndexesToCreate(schema, schemaIndexes, dbIndexes, toDrop); cb(null, { toDrop, toCreate }); }); }); }; -function getIndexesToCreate(schema, schemaIndexes, dbIndexes) { +function getIndexesToCreate(schema, schemaIndexes, dbIndexes, toDrop) { const toCreate = []; for (const [schemaIndexKeysObject, schemaIndexOptions] of schemaIndexes) { @@ -1589,7 +1589,10 @@ function getIndexesToCreate(schema, schemaIndexes, dbIndexes) { if (isDefaultIdIndex(index)) { continue; } - if (isIndexEqual(schemaIndexKeysObject, options, index)) { + if ( + isIndexEqual(schemaIndexKeysObject, options, index) && + !toDrop.includes(index.name) + ) { found = true; break; } @@ -1887,6 +1890,12 @@ function _ensureIndexes(model, options, callback) { indexOptions.background = options.background; } + if ('toCreate' in options) { + if (options.toCreate.length === 0) { + return done(); + } + } + model.collection.createIndex(indexFields, indexOptions, utils.tick(function(err, name) { indexSingleDone(err, indexFields, indexOptions, name); if (err) { diff --git a/test/model.test.js b/test/model.test.js index 3c6585db5ce..13dd3c8e097 100644 --- a/test/model.test.js +++ b/test/model.test.js @@ -6767,7 +6767,8 @@ describe('Model', function() { ); }); - xit('creates indexes only when they do not exist on the mongodb server (gh-12250)', async() => { + + it('creates indexes only when they do not exist on the mongodb server (gh-12250)', async() => { const userSchema = new Schema({ name: { type: String } }, { autoIndex: false }); @@ -6784,12 +6785,12 @@ describe('Model', function() { // Act await User.syncIndexes(); assert.equal(createIndexSpy.callCount, 1); - assert.equal(listIndexesSpy.callCount, 2); + assert.equal(listIndexesSpy.callCount, 1); await User.syncIndexes(); // Assert - assert.equal(listIndexesSpy.callCount, 4); + assert.equal(listIndexesSpy.callCount, 2); assert.equal(createIndexSpy.callCount, 1); }); }); From 0abf4517da710ec6dd7b9539f7b4036595a4ac95 Mon Sep 17 00:00:00 2001 From: Phillip Huang Date: Fri, 9 Dec 2022 09:17:45 -0800 Subject: [PATCH 08/23] add test --- test/types/schema.test.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/test/types/schema.test.ts b/test/types/schema.test.ts index e4bf39b313c..d873363a076 100644 --- a/test/types/schema.test.ts +++ b/test/types/schema.test.ts @@ -969,3 +969,12 @@ function gh12611() { anotherField?: string; }>({} as Props); } + +function gh12782() { + const schemaObj = { test: { type: String, required: true } }; + const schema = new Schema(schemaObj); + type Props = InferSchemaType; + expectType<{ + test: string + }>({} as Props); +} From f7f1ef2dc790363d6fbd2e6e0ccfdae16eaa316e Mon Sep 17 00:00:00 2001 From: Luca Pizzini Date: Sat, 10 Dec 2022 10:56:12 +0100 Subject: [PATCH 09/23] test trigger --- test/model.test.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/model.test.js b/test/model.test.js index 13dd3c8e097..6157f53e3b5 100644 --- a/test/model.test.js +++ b/test/model.test.js @@ -6782,14 +6782,13 @@ describe('Model', function() { const createIndexSpy = sinon.spy(User.collection, 'createIndex'); const listIndexesSpy = sinon.spy(User.collection, 'listIndexes'); - // Act await User.syncIndexes(); + assert.equal(createIndexSpy.callCount, 1); assert.equal(listIndexesSpy.callCount, 1); await User.syncIndexes(); - // Assert assert.equal(listIndexesSpy.callCount, 2); assert.equal(createIndexSpy.callCount, 1); }); From b4cb33a5fd92a7a177a8cce80e4dd3fa0e287cb7 Mon Sep 17 00:00:00 2001 From: Luca Pizzini Date: Sat, 10 Dec 2022 11:35:06 +0100 Subject: [PATCH 10/23] docs(middleware): fix broken links --- docs/middleware.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/middleware.md b/docs/middleware.md index 042e7ead637..094086f6ca2 100644 --- a/docs/middleware.md +++ b/docs/middleware.md @@ -206,7 +206,7 @@ error `err1` and then throw an error `err2`, mongoose will report `err1`.

Post middleware

-[post](schema.html#schema_Schema-post) middleware are executed _after_ +[post](api.html#schema_Schema-post) middleware are executed _after_ the hooked method and all of its `pre` middleware have completed. ```javascript @@ -334,8 +334,8 @@ doc.remove(); Model.remove(); ``` -You can pass options to [`Schema.pre()`](schema.html#schema_Schema-pre) -and [`Schema.post()`](schema.html#schema_Schema-post) to switch whether +You can pass options to [`Schema.pre()`](api.html#schema_Schema-pre) +and [`Schema.post()`](api.html#schema_Schema-post) to switch whether Mongoose calls your `remove()` hook for [`Document.remove()`](model.html#model_Model-remove) or [`Model.remove()`](model.html#model_Model-remove). Note here that you need to set both `document` and `query` properties in the passed object: From 310f45d252724fe26584bb52bbac20a7d8001f66 Mon Sep 17 00:00:00 2001 From: Luca Pizzini Date: Sun, 11 Dec 2022 10:45:24 +0100 Subject: [PATCH 11/23] docs(queries): fixed broken links fix #12789 --- docs/queries.md | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/docs/queries.md b/docs/queries.md index 08bc18243bb..10c6fb1cb25 100644 --- a/docs/queries.md +++ b/docs/queries.md @@ -5,21 +5,21 @@ for [CRUD operations](https://en.wikipedia.org/wiki/Create,_read,_update_and_del Each of these functions returns a [mongoose `Query` object](query.html#Query). -- [`Model.deleteMany()`](model.html#model_Model-deleteMany) -- [`Model.deleteOne()`](model.html#model_Model-deleteOne) -- [`Model.find()`](model.html#model_Model-find) -- [`Model.findById()`](model.html#model_Model-findById) -- [`Model.findByIdAndDelete()`](model.html#model_Model-findByIdAndDelete) -- [`Model.findByIdAndRemove()`](model.html#model_Model-findByIdAndRemove) -- [`Model.findByIdAndUpdate()`](model.html#model_Model-findByIdAndUpdate) -- [`Model.findOne()`](model.html#model_Model-findOne) -- [`Model.findOneAndDelete()`](model.html#model_Model-findOneAndDelete) -- [`Model.findOneAndRemove()`](model.html#model_Model-findOneAndRemove) -- [`Model.findOneAndReplace()`](model.html#model_Model-findOneAndReplace) -- [`Model.findOneAndUpdate()`](model.html#model_Model-findOneAndUpdate) -- [`Model.replaceOne()`](model.html#model_Model-replaceOne) -- [`Model.updateMany()`](model.html#model_Model-updateMany) -- [`Model.updateOne()`](model.html#model_Model-updateOne) +- [`Model.deleteMany()`](api.html#model_Model-deleteMany) +- [`Model.deleteOne()`](api.html#model_Model-deleteOne) +- [`Model.find()`](api.html#model_Model-find) +- [`Model.findById()`](api.html#model_Model-findById) +- [`Model.findByIdAndDelete()`](api.html#model_Model-findByIdAndDelete) +- [`Model.findByIdAndRemove()`](api.html#model_Model-findByIdAndRemove) +- [`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) +- [`Model.updateMany()`](api.html#model_Model-updateMany) +- [`Model.updateOne()`](api.html#model_Model-updateOne) A mongoose query can be executed in one of two ways. First, if you pass in a `callback` function, Mongoose will execute the query asynchronously @@ -57,7 +57,7 @@ will be null. If the query is successful, the `error` parameter will be null, an Anywhere a callback is passed to a query in Mongoose, the callback follows the pattern `callback(error, results)`. What `results` is depends on the operation: For `findOne()` it is a [potentially-null single document](api/model.html#model_Model-findOne), `find()` a [list of documents](api/model.html#model_Model-find), `count()` [the number of documents](api/model.html#model_Model-count), `update()` the [number of documents affected](api/model.html#model_Model-update), etc. -The [API docs for Models](api/model-js.html#model-js) provide more detail on what is passed to the callbacks. +The [API docs for Models](api/model.html) provide more detail on what is passed to the callbacks. Now let's look at what happens when no `callback` is passed: From 60b7f1c314537c3dd706951629ddd276cb2328f8 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Mon, 12 Dec 2022 08:02:51 -0700 Subject: [PATCH 12/23] chore: use axios 1.1.3 because axios 1.2.0 cant fetch opencollective sponsors --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 448ae0b8324..50942427dad 100644 --- a/package.json +++ b/package.json @@ -36,7 +36,7 @@ "acquit-ignore": "0.2.0", "acquit-require": "0.1.1", "assert-browserify": "2.0.0", - "axios": "1.2.0", + "axios": "1.1.3", "babel-loader": "8.2.5", "benchmark": "2.1.4", "bluebird": "3.7.2", From 02b0426c3848805bc0a7be0608833f49c004c021 Mon Sep 17 00:00:00 2001 From: Luca Pizzini Date: Wed, 14 Dec 2022 09:56:50 +0100 Subject: [PATCH 13/23] fix(query): update queries removes fields set to undefined fix #12794 --- lib/helpers/query/castUpdate.js | 10 + test/query.test.js | 2761 ++++++++++++++++++------------- 2 files changed, 1616 insertions(+), 1155 deletions(-) diff --git a/lib/helpers/query/castUpdate.js b/lib/helpers/query/castUpdate.js index 0a36104227e..50d56509610 100644 --- a/lib/helpers/query/castUpdate.js +++ b/lib/helpers/query/castUpdate.js @@ -84,6 +84,12 @@ module.exports = function castUpdate(schema, obj, options, context, filter) { const op = ops[i]; val = ret[op]; hasDollarKey = hasDollarKey || op.startsWith('$'); + const toUnset = {}; + for (const key of Object.keys(val)) { + if (val[key] === undefined) { + toUnset[key] = 1; + } + } if (val && typeof val === 'object' && @@ -100,6 +106,10 @@ module.exports = function castUpdate(schema, obj, options, context, filter) { if (op.startsWith('$') && utils.isEmptyObject(val)) { delete ret[op]; + if (op === '$set' && !utils.isEmptyObject(toUnset)) { + // Unset all undefined values + ret['$unset'] = toUnset; + } } } diff --git a/test/query.test.js b/test/query.test.js index 53e2dff58b3..c03689eeef8 100644 --- a/test/query.test.js +++ b/test/query.test.js @@ -19,14 +19,14 @@ const DocumentObjectId = mongoose.Types.ObjectId; * Test. */ -describe('Query', function() { +describe('Query', function () { let commentSchema; let productSchema; let db; - before(function() { + before(function () { commentSchema = new Schema({ - text: String + text: String, }); productSchema = new Schema({ @@ -35,15 +35,15 @@ describe('Query', function() { ids: [Schema.ObjectId], strings: [String], numbers: [Number], - comments: [commentSchema] + comments: [commentSchema], }); }); - before(function() { + before(function () { db = start(); }); - after(async function() { + after(async function () { await db.close(); }); @@ -51,8 +51,8 @@ describe('Query', function() { afterEach(() => util.clearTestData(db)); afterEach(() => require('./util').stopRemainingOps(db)); - describe('constructor', function() { - it('should not corrupt options', function(done) { + describe('constructor', function () { + it('should not corrupt options', function (done) { const opts = {}; const query = new Query({}, opts); assert.notEqual(opts, query._mongooseOptions); @@ -60,30 +60,30 @@ describe('Query', function() { }); }); - describe('select', function() { - it('(object)', function(done) { + describe('select', function () { + it('(object)', function (done) { const query = new Query({}); query.select({ a: 1, b: 1, c: 0 }); assert.deepEqual(query._fields, { a: 1, b: 1, c: 0 }); done(); }); - it('(string)', function(done) { + it('(string)', function (done) { const query = new Query({}); query.select(' a b -c '); assert.deepEqual(query._fields, { a: 1, b: 1, c: 0 }); done(); }); - it('("a","b","c")', function(done) { - assert.throws(function() { + it('("a","b","c")', function (done) { + assert.throws(function () { const query = new Query({}); query.select('a', 'b', 'c'); }, /Invalid select/); done(); }); - it('should not overwrite fields set in prior calls', function(done) { + it('should not overwrite fields set in prior calls', function (done) { const query = new Query({}); query.select('a'); assert.deepEqual(query._fields, { a: 1 }); @@ -96,45 +96,59 @@ describe('Query', function() { done(); }); - it('should remove existing fields from inclusive projection', function(done) { + it('should remove existing fields from inclusive projection', function (done) { const query = new Query({}); - query.select({ + query + .select({ + a: 1, + b: 1, + c: 1, + 'parent1.child1': 1, + 'parent1.child2': 1, + 'parent2.child1': 1, + 'parent2.child2': 1, + }) + .select({ b: 0, d: 1, 'c.child': 0, parent1: 0, 'parent2.child1': 0 }); + assert.deepEqual(query._fields, { a: 1, - b: 1, c: 1, - 'parent1.child1': 1, - 'parent1.child2': 1, - 'parent2.child1': 1, - 'parent2.child2': 1 - }).select({ b: 0, d: 1, 'c.child': 0, parent1: 0, 'parent2.child1': 0 }); - assert.deepEqual(query._fields, { a: 1, c: 1, d: 1, 'parent2.child2': 1 }); + d: 1, + 'parent2.child2': 1, + }); done(); }); - it('should remove existing fields from exclusive projection', function(done) { + it('should remove existing fields from exclusive projection', function (done) { const query = new Query({}); - query.select({ + query + .select({ + a: 0, + b: 0, + c: 0, + 'parent1.child1': 0, + 'parent1.child2': 0, + 'parent2.child1': 0, + 'parent2.child2': 0, + }) + .select({ b: 1, d: 0, 'c.child': 1, parent1: 1, 'parent2.child1': 1 }); + assert.deepEqual(query._fields, { a: 0, - b: 0, c: 0, - 'parent1.child1': 0, - 'parent1.child2': 0, - 'parent2.child1': 0, - 'parent2.child2': 0 - }).select({ b: 1, d: 0, 'c.child': 1, parent1: 1, 'parent2.child1': 1 }); - assert.deepEqual(query._fields, { a: 0, c: 0, d: 0, 'parent2.child2': 0 }); + d: 0, + 'parent2.child2': 0, + }); done(); }); }); - describe('projection() (gh-7384)', function() { - it('gets current projection', function() { + describe('projection() (gh-7384)', function () { + it('gets current projection', function () { const query = new Query({}); query.select('a'); assert.deepEqual(query.projection(), { a: 1 }); }); - it('overwrites current projection', function() { + it('overwrites current projection', function () { const query = new Query({}); query.select('a'); assert.deepEqual(query.projection({ b: 1 }), { b: 1 }); @@ -142,8 +156,8 @@ describe('Query', function() { }); }); - describe('where', function() { - it('works', function(done) { + describe('where', function () { + it('works', function (done) { const query = new Query({}); query.where('name', 'guillermo'); assert.deepEqual(query._conditions, { name: 'guillermo' }); @@ -152,27 +166,27 @@ describe('Query', function() { assert.deepEqual(query._conditions, { name: 'guillermo', a: 'b' }); done(); }); - it('throws if non-string or non-object path is passed', function(done) { + it('throws if non-string or non-object path is passed', function (done) { const query = new Query({}); - assert.throws(function() { + assert.throws(function () { query.where(50); }); - assert.throws(function() { + assert.throws(function () { query.where([]); }); done(); }); - it('does not throw when 0 args passed', function(done) { + it('does not throw when 0 args passed', function (done) { const query = new Query({}); - assert.doesNotThrow(function() { + assert.doesNotThrow(function () { query.where(); }); done(); }); }); - describe('equals', function() { - it('works', function(done) { + describe('equals', function () { + it('works', function (done) { const query = new Query({}); query.where('name').equals('guillermo'); assert.deepEqual(query._conditions, { name: 'guillermo' }); @@ -180,14 +194,14 @@ describe('Query', function() { }); }); - describe('gte', function() { - it('with 2 args', function(done) { + describe('gte', function () { + it('with 2 args', function (done) { const query = new Query({}); query.gte('age', 18); assert.deepEqual(query._conditions, { age: { $gte: 18 } }); done(); }); - it('with 1 arg', function(done) { + it('with 1 arg', function (done) { const query = new Query({}); query.where('age').gte(18); assert.deepEqual(query._conditions, { age: { $gte: 18 } }); @@ -195,14 +209,14 @@ describe('Query', function() { }); }); - describe('gt', function() { - it('with 1 arg', function(done) { + describe('gt', function () { + it('with 1 arg', function (done) { const query = new Query({}); query.where('age').gt(17); assert.deepEqual(query._conditions, { age: { $gt: 17 } }); done(); }); - it('with 2 args', function(done) { + it('with 2 args', function (done) { const query = new Query({}); query.gt('age', 17); assert.deepEqual(query._conditions, { age: { $gt: 17 } }); @@ -210,14 +224,14 @@ describe('Query', function() { }); }); - describe('lte', function() { - it('with 1 arg', function(done) { + describe('lte', function () { + it('with 1 arg', function (done) { const query = new Query({}); query.where('age').lte(65); assert.deepEqual(query._conditions, { age: { $lte: 65 } }); done(); }); - it('with 2 args', function(done) { + it('with 2 args', function (done) { const query = new Query({}); query.lte('age', 65); assert.deepEqual(query._conditions, { age: { $lte: 65 } }); @@ -225,14 +239,14 @@ describe('Query', function() { }); }); - describe('lt', function() { - it('with 1 arg', function(done) { + describe('lt', function () { + it('with 1 arg', function (done) { const query = new Query({}); query.where('age').lt(66); assert.deepEqual(query._conditions, { age: { $lt: 66 } }); done(); }); - it('with 2 args', function(done) { + it('with 2 args', function (done) { const query = new Query({}); query.lt('age', 66); assert.deepEqual(query._conditions, { age: { $lt: 66 } }); @@ -240,9 +254,9 @@ describe('Query', function() { }); }); - describe('combined', function() { - describe('lt and gt', function() { - it('works', function(done) { + describe('combined', function () { + describe('lt and gt', function () { + it('works', function (done) { const query = new Query({}); query.where('age').lt(66).gt(17); assert.deepEqual(query._conditions, { age: { $lt: 66, $gt: 17 } }); @@ -251,25 +265,26 @@ describe('Query', function() { }); }); - describe('tl on one path and gt on another', function() { - it('works', function(done) { + describe('tl on one path and gt on another', function () { + it('works', function (done) { const query = new Query({}); - query - .where('age').lt(66) - .where('height').gt(5); - assert.deepEqual(query._conditions, { age: { $lt: 66 }, height: { $gt: 5 } }); + query.where('age').lt(66).where('height').gt(5); + assert.deepEqual(query._conditions, { + age: { $lt: 66 }, + height: { $gt: 5 }, + }); done(); }); }); - describe('ne', function() { - it('with 1 arg', function(done) { + describe('ne', function () { + it('with 1 arg', function (done) { const query = new Query({}); query.where('age').ne(21); assert.deepEqual(query._conditions, { age: { $ne: 21 } }); done(); }); - it('with 2 args', function(done) { + it('with 2 args', function (done) { const query = new Query({}); query.ne('age', 21); assert.deepEqual(query._conditions, { age: { $ne: 21 } }); @@ -277,26 +292,26 @@ describe('Query', function() { }); }); - describe('in', function() { - it('with 1 arg', function(done) { + describe('in', function () { + it('with 1 arg', function (done) { const query = new Query({}); query.where('age').in([21, 25, 30]); assert.deepEqual(query._conditions, { age: { $in: [21, 25, 30] } }); done(); }); - it('with 2 args', function(done) { + it('with 2 args', function (done) { const query = new Query({}); query.in('age', [21, 25, 30]); assert.deepEqual(query._conditions, { age: { $in: [21, 25, 30] } }); done(); }); - it('where a non-array value no via where', function(done) { + it('where a non-array value no via where', function (done) { const query = new Query({}); query.in('age', 21); assert.deepEqual(query._conditions, { age: { $in: 21 } }); done(); }); - it('where a non-array value via where', function(done) { + it('where a non-array value via where', function (done) { const query = new Query({}); query.where('age').in(21); assert.deepEqual(query._conditions, { age: { $in: 21 } }); @@ -304,26 +319,26 @@ describe('Query', function() { }); }); - describe('nin', function() { - it('with 1 arg', function(done) { + describe('nin', function () { + it('with 1 arg', function (done) { const query = new Query({}); query.where('age').nin([21, 25, 30]); assert.deepEqual(query._conditions, { age: { $nin: [21, 25, 30] } }); done(); }); - it('with 2 args', function(done) { + it('with 2 args', function (done) { const query = new Query({}); query.nin('age', [21, 25, 30]); assert.deepEqual(query._conditions, { age: { $nin: [21, 25, 30] } }); done(); }); - it('with a non-array value not via where', function(done) { + it('with a non-array value not via where', function (done) { const query = new Query({}); query.nin('age', 21); assert.deepEqual(query._conditions, { age: { $nin: 21 } }); done(); }); - it('with a non-array value via where', function(done) { + it('with a non-array value via where', function (done) { const query = new Query({}); query.where('age').nin(21); assert.deepEqual(query._conditions, { age: { $nin: 21 } }); @@ -331,26 +346,26 @@ describe('Query', function() { }); }); - describe('mod', function() { - it('not via where, where [a, b] param', function(done) { + describe('mod', function () { + it('not via where, where [a, b] param', function (done) { const query = new Query({}); query.mod('age', [5, 2]); assert.deepEqual(query._conditions, { age: { $mod: [5, 2] } }); done(); }); - it('not via where, where a and b params', function(done) { + it('not via where, where a and b params', function (done) { const query = new Query({}); query.mod('age', 5, 2); assert.deepEqual(query._conditions, { age: { $mod: [5, 2] } }); done(); }); - it('via where, where [a, b] param', function(done) { + it('via where, where [a, b] param', function (done) { const query = new Query({}); query.where('age').mod([5, 2]); assert.deepEqual(query._conditions, { age: { $mod: [5, 2] } }); done(); }); - it('via where, where a and b params', function(done) { + it('via where, where a and b params', function (done) { const query = new Query({}); query.where('age').mod(5, 2); assert.deepEqual(query._conditions, { age: { $mod: [5, 2] } }); @@ -358,123 +373,169 @@ describe('Query', function() { }); }); - describe('near', function() { - it('via where, where { center :[lat, long]} param', function(done) { + describe('near', function () { + it('via where, where { center :[lat, long]} param', function (done) { const query = new Query({}); query.where('checkin').near({ center: [40, -72] }); assert.deepEqual(query._conditions, { checkin: { $near: [40, -72] } }); done(); }); - it('via where, where [lat, long] param', function(done) { + it('via where, where [lat, long] param', function (done) { const query = new Query({}); query.where('checkin').near([40, -72]); assert.deepEqual(query._conditions, { checkin: { $near: [40, -72] } }); done(); }); - it('via where, where lat and long params', function(done) { + it('via where, where lat and long params', function (done) { const query = new Query({}); query.where('checkin').near(40, -72); assert.deepEqual(query._conditions, { checkin: { $near: [40, -72] } }); done(); }); - it('not via where, where [lat, long] param', function(done) { + it('not via where, where [lat, long] param', function (done) { const query = new Query({}); query.near('checkin', [40, -72]); assert.deepEqual(query._conditions, { checkin: { $near: [40, -72] } }); done(); }); - it('not via where, where lat and long params', function(done) { + it('not via where, where lat and long params', function (done) { const query = new Query({}); query.near('checkin', 40, -72); assert.deepEqual(query._conditions, { checkin: { $near: [40, -72] } }); done(); }); - it('via where, where GeoJSON param', function(done) { + it('via where, where GeoJSON param', function (done) { const query = new Query({}); - query.where('numbers').near({ center: { type: 'Point', coordinates: [40, -72] } }); - assert.deepEqual(query._conditions, { numbers: { $near: { $geometry: { type: 'Point', coordinates: [40, -72] } } } }); - assert.doesNotThrow(function() { + query + .where('numbers') + .near({ center: { type: 'Point', coordinates: [40, -72] } }); + assert.deepEqual(query._conditions, { + numbers: { + $near: { $geometry: { type: 'Point', coordinates: [40, -72] } }, + }, + }); + assert.doesNotThrow(function () { query.cast(db.model('Product', productSchema)); }); done(); }); - it('with path, where GeoJSON param', function(done) { + it('with path, where GeoJSON param', function (done) { const query = new Query({}); query.near('loc', { center: { type: 'Point', coordinates: [40, -72] } }); - assert.deepEqual(query._conditions, { loc: { $near: { $geometry: { type: 'Point', coordinates: [40, -72] } } } }); + assert.deepEqual(query._conditions, { + loc: { + $near: { $geometry: { type: 'Point', coordinates: [40, -72] } }, + }, + }); done(); }); }); - describe('nearSphere', function() { - it('via where, where [lat, long] param', function(done) { + describe('nearSphere', function () { + it('via where, where [lat, long] param', function (done) { const query = new Query({}); query.where('checkin').nearSphere([40, -72]); - assert.deepEqual(query._conditions, { checkin: { $nearSphere: [40, -72] } }); + assert.deepEqual(query._conditions, { + checkin: { $nearSphere: [40, -72] }, + }); done(); }); - it('via where, where lat and long params', function(done) { + it('via where, where lat and long params', function (done) { const query = new Query({}); query.where('checkin').nearSphere(40, -72); - assert.deepEqual(query._conditions, { checkin: { $nearSphere: [40, -72] } }); + assert.deepEqual(query._conditions, { + checkin: { $nearSphere: [40, -72] }, + }); done(); }); - it('not via where, where [lat, long] param', function(done) { + it('not via where, where [lat, long] param', function (done) { const query = new Query({}); query.nearSphere('checkin', [40, -72]); - assert.deepEqual(query._conditions, { checkin: { $nearSphere: [40, -72] } }); + assert.deepEqual(query._conditions, { + checkin: { $nearSphere: [40, -72] }, + }); done(); }); - it('not via where, where lat and long params', function(done) { + it('not via where, where lat and long params', function (done) { const query = new Query({}); query.nearSphere('checkin', 40, -72); - assert.deepEqual(query._conditions, { checkin: { $nearSphere: [40, -72] } }); + assert.deepEqual(query._conditions, { + checkin: { $nearSphere: [40, -72] }, + }); done(); }); - it('via where, with object', function(done) { + it('via where, with object', function (done) { const query = new Query({}); query.where('checkin').nearSphere({ center: [20, 23], maxDistance: 2 }); - assert.deepEqual(query._conditions, { checkin: { $nearSphere: [20, 23], $maxDistance: 2 } }); + assert.deepEqual(query._conditions, { + checkin: { $nearSphere: [20, 23], $maxDistance: 2 }, + }); done(); }); - it('via where, where GeoJSON param', function(done) { + it('via where, where GeoJSON param', function (done) { const query = new Query({}); - query.where('numbers').nearSphere({ center: { type: 'Point', coordinates: [40, -72] } }); - assert.deepEqual(query._conditions, { numbers: { $nearSphere: { $geometry: { type: 'Point', coordinates: [40, -72] } } } }); - assert.doesNotThrow(function() { + query + .where('numbers') + .nearSphere({ center: { type: 'Point', coordinates: [40, -72] } }); + assert.deepEqual(query._conditions, { + numbers: { + $nearSphere: { $geometry: { type: 'Point', coordinates: [40, -72] } }, + }, + }); + assert.doesNotThrow(function () { query.cast(db.model('Product', productSchema)); }); done(); }); - it('with path, with GeoJSON', function(done) { + it('with path, with GeoJSON', function (done) { const query = new Query({}); - query.nearSphere('numbers', { center: { type: 'Point', coordinates: [40, -72] } }); - assert.deepEqual(query._conditions, { numbers: { $nearSphere: { $geometry: { type: 'Point', coordinates: [40, -72] } } } }); - assert.doesNotThrow(function() { + query.nearSphere('numbers', { + center: { type: 'Point', coordinates: [40, -72] }, + }); + assert.deepEqual(query._conditions, { + numbers: { + $nearSphere: { $geometry: { type: 'Point', coordinates: [40, -72] } }, + }, + }); + assert.doesNotThrow(function () { query.cast(db.model('Product', productSchema)); }); done(); }); }); - describe('maxDistance', function() { - it('via where', function(done) { + describe('maxDistance', function () { + it('via where', function (done) { const query = new Query({}); query.where('checkin').near([40, -72]).maxDistance(1); - assert.deepEqual(query._conditions, { checkin: { $near: [40, -72], $maxDistance: 1 } }); + assert.deepEqual(query._conditions, { + checkin: { $near: [40, -72], $maxDistance: 1 }, + }); done(); }); }); - describe('within', function() { - describe('box', function() { - it('via where', function(done) { + describe('within', function () { + describe('box', function () { + it('via where', function (done) { const query = new Query({}); - query.where('gps').within().box({ ll: [5, 25], ur: [10, 30] }); - const match = { gps: { $within: { $box: [[5, 25], [10, 30]] } } }; + query + .where('gps') + .within() + .box({ ll: [5, 25], ur: [10, 30] }); + const match = { + gps: { + $within: { + $box: [ + [5, 25], + [10, 30], + ], + }, + }, + }; if (Query.use$geoWithin) { match.gps.$geoWithin = match.gps.$within; delete match.gps.$within; @@ -482,10 +543,19 @@ describe('Query', function() { assert.deepEqual(query._conditions, match); done(); }); - it('via where, no object', function(done) { + it('via where, no object', function (done) { const query = new Query({}); query.where('gps').within().box([5, 25], [10, 30]); - const match = { gps: { $within: { $box: [[5, 25], [10, 30]] } } }; + const match = { + gps: { + $within: { + $box: [ + [5, 25], + [10, 30], + ], + }, + }, + }; if (Query.use$geoWithin) { match.gps.$geoWithin = match.gps.$within; delete match.gps.$within; @@ -495,10 +565,13 @@ describe('Query', function() { }); }); - describe('center', function() { - it('via where', function(done) { + describe('center', function () { + it('via where', function (done) { const query = new Query({}); - query.where('gps').within().center({ center: [5, 25], radius: 5 }); + query + .where('gps') + .within() + .center({ center: [5, 25], radius: 5 }); const match = { gps: { $within: { $center: [[5, 25], 5] } } }; if (Query.use$geoWithin) { match.gps.$geoWithin = match.gps.$within; @@ -509,10 +582,13 @@ describe('Query', function() { }); }); - describe('centerSphere', function() { - it('via where', function(done) { + describe('centerSphere', function () { + it('via where', function (done) { const query = new Query({}); - query.where('gps').within().centerSphere({ center: [5, 25], radius: 5 }); + query + .where('gps') + .within() + .centerSphere({ center: [5, 25], radius: 5 }); const match = { gps: { $within: { $centerSphere: [[5, 25], 5] } } }; if (Query.use$geoWithin) { match.gps.$geoWithin = match.gps.$within; @@ -523,11 +599,30 @@ describe('Query', function() { }); }); - describe('polygon', function() { - it('via where', function(done) { + describe('polygon', function () { + it('via where', function (done) { const query = new Query({}); - query.where('gps').within().polygon({ a: { x: 10, y: 20 }, b: { x: 15, y: 25 }, c: { x: 20, y: 20 } }); - const match = { gps: { $within: { $polygon: [{ a: { x: 10, y: 20 }, b: { x: 15, y: 25 }, c: { x: 20, y: 20 } }] } } }; + query + .where('gps') + .within() + .polygon({ + a: { x: 10, y: 20 }, + b: { x: 15, y: 25 }, + c: { x: 20, y: 20 }, + }); + const match = { + gps: { + $within: { + $polygon: [ + { + a: { x: 10, y: 20 }, + b: { x: 15, y: 25 }, + c: { x: 20, y: 20 }, + }, + ], + }, + }, + }; if (Query.use$geoWithin) { match.gps.$geoWithin = match.gps.$within; delete match.gps.$within; @@ -538,27 +633,27 @@ describe('Query', function() { }); }); - describe('exists', function() { - it('0 args via where', function(done) { + describe('exists', function () { + it('0 args via where', function (done) { const query = new Query({}); query.where('username').exists(); assert.deepEqual(query._conditions, { username: { $exists: true } }); done(); }); - it('1 arg via where', function(done) { + it('1 arg via where', function (done) { const query = new Query({}); query.where('username').exists(false); assert.deepEqual(query._conditions, { username: { $exists: false } }); done(); }); - it('where 1 argument not via where', function(done) { + it('where 1 argument not via where', function (done) { const query = new Query({}); query.exists('username'); assert.deepEqual(query._conditions, { username: { $exists: true } }); done(); }); - it('where 2 args not via where', function(done) { + it('where 2 args not via where', function (done) { const query = new Query({}); query.exists('username', false); assert.deepEqual(query._conditions, { username: { $exists: false } }); @@ -566,29 +661,33 @@ describe('Query', function() { }); }); - describe('all', function() { - it('via where', function(done) { + describe('all', function () { + it('via where', function (done) { const query = new Query({}); query.where('pets').all(['dog', 'cat', 'ferret']); - assert.deepEqual(query._conditions, { pets: { $all: ['dog', 'cat', 'ferret'] } }); + assert.deepEqual(query._conditions, { + pets: { $all: ['dog', 'cat', 'ferret'] }, + }); done(); }); - it('not via where', function(done) { + it('not via where', function (done) { const query = new Query({}); query.all('pets', ['dog', 'cat', 'ferret']); - assert.deepEqual(query._conditions, { pets: { $all: ['dog', 'cat', 'ferret'] } }); + assert.deepEqual(query._conditions, { + pets: { $all: ['dog', 'cat', 'ferret'] }, + }); done(); }); }); - describe('find', function() { - it('strict array equivalence condition v', function(done) { + describe('find', function () { + it('strict array equivalence condition v', function (done) { const query = new Query({}); query.find({ pets: ['dog', 'cat', 'ferret'] }); assert.deepEqual(query._conditions, { pets: ['dog', 'cat', 'ferret'] }); done(); }); - it('with no args', function(done) { + it('with no args', function (done) { let threw = false; const q = new Query({}); @@ -602,9 +701,9 @@ describe('Query', function() { done(); }); - it('works with overwriting previous object args (1176)', function(done) { + it('works with overwriting previous object args (1176)', function (done) { const q = new Query({}); - assert.doesNotThrow(function() { + assert.doesNotThrow(function () { q.find({ age: { $lt: 30 } }); q.find({ age: 20 }); // overwrite }); @@ -613,14 +712,14 @@ describe('Query', function() { }); }); - describe('size', function() { - it('via where', function(done) { + describe('size', function () { + it('via where', function (done) { const query = new Query({}); query.where('collection').size(5); assert.deepEqual(query._conditions, { collection: { $size: 5 } }); done(); }); - it('not via where', function(done) { + it('not via where', function (done) { const query = new Query({}); query.size('collection', 5); assert.deepEqual(query._conditions, { collection: { $size: 5 } }); @@ -628,74 +727,74 @@ describe('Query', function() { }); }); - describe('slice', function() { - it('where and positive limit param', function(done) { + describe('slice', function () { + it('where and positive limit param', function (done) { const query = new Query({}); query.where('collection').slice(5); assert.deepEqual(query._fields, { collection: { $slice: 5 } }); done(); }); - it('where just negative limit param', function(done) { + it('where just negative limit param', function (done) { const query = new Query({}); query.where('collection').slice(-5); assert.deepEqual(query._fields, { collection: { $slice: -5 } }); done(); }); - it('where [skip, limit] param', function(done) { + it('where [skip, limit] param', function (done) { const query = new Query({}); query.where('collection').slice([14, 10]); // Return the 15th through 25th assert.deepEqual(query._fields, { collection: { $slice: [14, 10] } }); done(); }); - it('where skip and limit params', function(done) { + it('where skip and limit params', function (done) { const query = new Query({}); query.where('collection').slice(14, 10); // Return the 15th through 25th assert.deepEqual(query._fields, { collection: { $slice: [14, 10] } }); done(); }); - it('where just positive limit param', function(done) { + it('where just positive limit param', function (done) { const query = new Query({}); query.where('collection').slice(5); assert.deepEqual(query._fields, { collection: { $slice: 5 } }); done(); }); - it('where just negative limit param', function(done) { + it('where just negative limit param', function (done) { const query = new Query({}); query.where('collection').slice(-5); assert.deepEqual(query._fields, { collection: { $slice: -5 } }); done(); }); - it('where the [skip, limit] param', function(done) { + it('where the [skip, limit] param', function (done) { const query = new Query({}); query.where('collection').slice([14, 10]); // Return the 15th through 25th assert.deepEqual(query._fields, { collection: { $slice: [14, 10] } }); done(); }); - it('where the skip and limit params', function(done) { + it('where the skip and limit params', function (done) { const query = new Query({}); query.where('collection').slice(14, 10); // Return the 15th through 25th assert.deepEqual(query._fields, { collection: { $slice: [14, 10] } }); done(); }); - it('not via where, with just positive limit param', function(done) { + it('not via where, with just positive limit param', function (done) { const query = new Query({}); query.slice('collection', 5); assert.deepEqual(query._fields, { collection: { $slice: 5 } }); done(); }); - it('not via where, where just negative limit param', function(done) { + it('not via where, where just negative limit param', function (done) { const query = new Query({}); query.slice('collection', -5); assert.deepEqual(query._fields, { collection: { $slice: -5 } }); done(); }); - it('not via where, where [skip, limit] param', function(done) { + it('not via where, where [skip, limit] param', function (done) { const query = new Query({}); query.slice('collection', [14, 10]); // Return the 15th through 25th assert.deepEqual(query._fields, { collection: { $slice: [14, 10] } }); done(); }); - it('not via where, where skip and limit params', function(done) { + it('not via where, where skip and limit params', function (done) { const query = new Query({}); query.slice('collection', 14, 10); // Return the 15th through 25th assert.deepEqual(query._fields, { collection: { $slice: [14, 10] } }); @@ -703,45 +802,55 @@ describe('Query', function() { }); }); - describe('elemMatch', function() { - describe('not via where', function() { - it('works', function(done) { + describe('elemMatch', function () { + describe('not via where', function () { + it('works', function (done) { const query = new Query({}); query.elemMatch('comments', { author: 'bnoguchi', votes: { $gte: 5 } }); - assert.deepEqual(query._conditions, { comments: { $elemMatch: { author: 'bnoguchi', votes: { $gte: 5 } } } }); + assert.deepEqual(query._conditions, { + comments: { $elemMatch: { author: 'bnoguchi', votes: { $gte: 5 } } }, + }); done(); }); - it('where block notation', function(done) { + it('where block notation', function (done) { const query = new Query({}); - query.elemMatch('comments', function(elem) { + query.elemMatch('comments', function (elem) { elem.where('author', 'bnoguchi'); elem.where('votes').gte(5); }); - assert.deepEqual(query._conditions, { comments: { $elemMatch: { author: 'bnoguchi', votes: { $gte: 5 } } } }); + assert.deepEqual(query._conditions, { + comments: { $elemMatch: { author: 'bnoguchi', votes: { $gte: 5 } } }, + }); done(); }); }); - describe('via where', function() { - it('works', function(done) { + describe('via where', function () { + it('works', function (done) { const query = new Query({}); - query.where('comments').elemMatch({ author: 'bnoguchi', votes: { $gte: 5 } }); - assert.deepEqual(query._conditions, { comments: { $elemMatch: { author: 'bnoguchi', votes: { $gte: 5 } } } }); + query + .where('comments') + .elemMatch({ author: 'bnoguchi', votes: { $gte: 5 } }); + assert.deepEqual(query._conditions, { + comments: { $elemMatch: { author: 'bnoguchi', votes: { $gte: 5 } } }, + }); done(); }); - it('where block notation', function(done) { + it('where block notation', function (done) { const query = new Query({}); - query.where('comments').elemMatch(function(elem) { + query.where('comments').elemMatch(function (elem) { elem.where('author', 'bnoguchi'); elem.where('votes').gte(5); }); - assert.deepEqual(query._conditions, { comments: { $elemMatch: { author: 'bnoguchi', votes: { $gte: 5 } } } }); + assert.deepEqual(query._conditions, { + comments: { $elemMatch: { author: 'bnoguchi', votes: { $gte: 5 } } }, + }); done(); }); }); }); - describe('$where', function() { - it('function arg', function(done) { + describe('$where', function () { + it('function arg', function (done) { const query = new Query({}); function filter() { @@ -752,23 +861,25 @@ describe('Query', function() { assert.deepEqual(query._conditions, { $where: filter }); done(); }); - it('string arg', function(done) { + it('string arg', function (done) { const query = new Query({}); query.$where('this.lastName === this.firstName'); - assert.deepEqual(query._conditions, { $where: 'this.lastName === this.firstName' }); + assert.deepEqual(query._conditions, { + $where: 'this.lastName === this.firstName', + }); done(); }); }); - describe('limit', function() { - it('works', function(done) { + describe('limit', function () { + it('works', function (done) { const query = new Query({}); query.limit(5); assert.strictEqual(query.options.limit, 5); done(); }); - it('with string limit (gh-11017)', function() { + it('with string limit (gh-11017)', function () { const query = new Query({}); query.limit('5'); assert.strictEqual(query.options.limit, 5); @@ -777,8 +888,8 @@ describe('Query', function() { }); }); - describe('skip', function() { - it('works', function(done) { + describe('skip', function () { + it('works', function (done) { const query = new Query({}); query.skip(9); assert.equal(query.options.skip, 9); @@ -786,8 +897,8 @@ describe('Query', function() { }); }); - describe('sort', function() { - it('works', function(done) { + describe('sort', function () { + it('works', function (done) { let query = new Query({}); query.sort('a -c b'); assert.deepEqual(query.options.sort, { a: 1, c: -1, b: 1 }); @@ -812,7 +923,10 @@ describe('Query', function() { } assert.ok(e, 'uh oh. no error was thrown'); - assert.equal(e.message, 'Invalid sort() argument, must be array of arrays'); + assert.equal( + e.message, + 'Invalid sort() argument, must be array of arrays' + ); e = undefined; try { @@ -826,12 +940,12 @@ describe('Query', function() { }); }); - describe('or', function() { - it('works', function(done) { + describe('or', function () { + it('works', function (done) { const query = new Query(); query.find({ $or: [{ x: 1 }, { x: 2 }] }); assert.equal(query._conditions.$or.length, 2); - query.or([{ y: 'We\'re under attack' }, { z: 47 }]); + query.or([{ y: "We're under attack" }, { z: 47 }]); assert.equal(query._conditions.$or.length, 4); assert.equal(query._conditions.$or[3].z, 47); query.or({ z: 'phew' }); @@ -842,27 +956,27 @@ describe('Query', function() { }); }); - describe('and', function() { - it('works', function(done) { + describe('and', function () { + it('works', function (done) { const query = new Query(); query.find({ $and: [{ x: 1 }, { y: 2 }] }); assert.equal(query._conditions.$and.length, 2); - query.and([{ z: 'We\'re under attack' }, { w: 47 }]); + query.and([{ z: "We're under attack" }, { w: 47 }]); assert.equal(query._conditions.$and.length, 4); assert.equal(query._conditions.$and[3].w, 47); query.and({ a: 'phew' }); assert.equal(query._conditions.$and.length, 5); assert.equal(query._conditions.$and[0].x, 1); assert.equal(query._conditions.$and[1].y, 2); - assert.equal(query._conditions.$and[2].z, 'We\'re under attack'); + assert.equal(query._conditions.$and[2].z, "We're under attack"); assert.equal(query._conditions.$and[3].w, 47); assert.equal(query._conditions.$and[4].a, 'phew'); done(); }); }); - describe('populate', function() { - it('converts to PopulateOptions objects', function(done) { + describe('populate', function () { + it('converts to PopulateOptions objects', function (done) { const q = new Query({}); const o = { path: 'yellow.brick', @@ -871,20 +985,20 @@ describe('Query', function() { model: undefined, options: undefined, _docs: {}, - _childDocs: [] + _childDocs: [], }; q.populate(o); assert.deepEqual(o, q._mongooseOptions.populate['yellow.brick']); done(); }); - it('overwrites duplicate paths', function(done) { + it('overwrites duplicate paths', function (done) { const q = new Query({}); let o = { path: 'yellow.brick', match: { bricks: { $lt: 1000 } }, _docs: {}, - _childDocs: [] + _childDocs: [], }; q.populate(Object.assign({}, o)); assert.equal(Object.keys(q._mongooseOptions.populate).length, 1); @@ -894,80 +1008,78 @@ describe('Query', function() { o = { path: 'yellow.brick', _docs: {}, - _childDocs: [] + _childDocs: [], }; assert.equal(Object.keys(q._mongooseOptions.populate).length, 1); assert.deepEqual(q._mongooseOptions.populate['yellow.brick'], o); done(); }); - it('accepts space delimited strings', function(done) { + it('accepts space delimited strings', function (done) { const q = new Query({}); q.populate('yellow.brick dirt'); assert.equal(Object.keys(q._mongooseOptions.populate).length, 2); assert.deepEqual(q._mongooseOptions.populate['yellow.brick'], { path: 'yellow.brick', _docs: {}, - _childDocs: [] + _childDocs: [], }); assert.deepEqual(q._mongooseOptions.populate['dirt'], { path: 'dirt', _docs: {}, - _childDocs: [] + _childDocs: [], }); done(); }); }); - describe('casting', function() { - it('to an array of mixed', function(done) { + describe('casting', function () { + it('to an array of mixed', function (done) { const query = new Query({}); const Product = db.model('Product', productSchema); - const params = { _id: new DocumentObjectId(), tags: { $in: [4, 8, 15, 16] } }; + const params = { + _id: new DocumentObjectId(), + tags: { $in: [4, 8, 15, 16] }, + }; query.cast(Product, params); assert.deepEqual(params.tags.$in, [4, 8, 15, 16]); done(); }); - it('doesn\'t wipe out $in (gh-6439)', async function() { - const embeddedSchema = new Schema({ - name: String - }, { _id: false }); + it("doesn't wipe out $in (gh-6439)", async function () { + const embeddedSchema = new Schema( + { + name: String, + }, + { _id: false } + ); const catSchema = new Schema({ name: String, - props: [embeddedSchema] + props: [embeddedSchema], }); const Cat = db.model('Cat', catSchema); const kitty = new Cat({ name: 'Zildjian', - props: [ - { name: 'invalid' }, - { name: 'abc' }, - { name: 'def' } - ] + props: [{ name: 'invalid' }, { name: 'abc' }, { name: 'def' }], }); - await kitty.save(); const cond = { _id: kitty._id }; const update = { $pull: { props: { - $in: [ - { name: 'invalid' }, - { name: 'def' } - ] - } - } + $in: [{ name: 'invalid' }, { name: 'def' }], + }, + }, }; await Cat.updateOne(cond, update); const found = await Cat.findOne(cond); assert.strictEqual(found.props[0].name, 'abc'); }); - it('find $ne should not cast single value to array for schematype of Array', function(done) { + it('find $ne should not cast single value to array for schematype of Array', function (done) { const query = new Query({}); const Product = db.model('Product', productSchema); const Comment = db.model('Comment', commentSchema); @@ -981,7 +1093,7 @@ describe('Query', function() { ids: { $ne: id }, comments: { $ne: comment }, strings: { $ne: 'Hi there' }, - numbers: { $ne: 10000 } + numbers: { $ne: 10000 }, }; query.cast(Product, params); @@ -1011,12 +1123,12 @@ describe('Query', function() { done(); }); - it('subdocument array with $ne: null should not throw', function(done) { + it('subdocument array with $ne: null should not throw', function (done) { const query = new Query({}); const Product = db.model('Product', productSchema); const params = { - comments: { $ne: null } + comments: { $ne: null }, }; query.cast(Product, params); @@ -1024,7 +1136,7 @@ describe('Query', function() { done(); }); - it('find should not cast single value to array for schematype of Array', function(done) { + it('find should not cast single value to array for schematype of Array', function (done) { const query = new Query({}); const Product = db.model('Product', productSchema); const Comment = db.model('Comment', commentSchema); @@ -1038,7 +1150,7 @@ describe('Query', function() { ids: id, comments: comment, strings: 'Hi there', - numbers: 10000 + numbers: 10000, }; query.cast(Product, params); @@ -1068,10 +1180,13 @@ describe('Query', function() { done(); }); - it('an $elemMatch with $in works (gh-1100)', function(done) { + it('an $elemMatch with $in works (gh-1100)', function (done) { const query = new Query({}); const Product = db.model('Product', productSchema); - const ids = [String(new DocumentObjectId()), String(new DocumentObjectId())]; + const ids = [ + String(new DocumentObjectId()), + String(new DocumentObjectId()), + ]; const params = { ids: { $elemMatch: { $in: ids } } }; query.cast(Product, params); assert.ok(params.ids.$elemMatch.$in[0] instanceof DocumentObjectId); @@ -1081,7 +1196,7 @@ describe('Query', function() { done(); }); - it('inequality operators for an array', function(done) { + it('inequality operators for an array', function (done) { const query = new Query({}); const Product = db.model('Product', productSchema); const Comment = db.model('Comment', commentSchema); @@ -1094,7 +1209,7 @@ describe('Query', function() { ids: { $gt: id }, comments: { $gt: comment }, strings: { $gt: 'Hi there' }, - numbers: { $gt: 10000 } + numbers: { $gt: 10000 }, }; query.cast(Product, params); @@ -1106,8 +1221,8 @@ describe('Query', function() { }); }); - describe('distinct', function() { - it('op', function() { + describe('distinct', function () { + it('op', function () { const q = new Query({}); q.distinct('blah'); @@ -1116,14 +1231,14 @@ describe('Query', function() { }); }); - describe('findOne', function() { - it('sets the op', function(done) { + describe('findOne', function () { + it('sets the op', function (done) { const Product = db.model('Product', productSchema); const prod = new Product({}); const q = new Query(prod.collection, {}, Product).distinct(); // use a timeout here because we have to wait for the connection to start // before any ops will get set - setTimeout(function() { + setTimeout(function () { assert.equal(q.op, 'distinct'); q.findOne(); assert.equal(q.op, 'findOne'); @@ -1131,23 +1246,25 @@ describe('Query', function() { }, 50); }); - it('works as a promise', function(done) { + it('works as a promise', function (done) { const Product = db.model('Product', productSchema); const promise = Product.findOne(); - promise.then(function() { - done(); - }, function(err) { - assert.ifError(err); - }); + promise.then( + function () { + done(); + }, + function (err) { + assert.ifError(err); + } + ); }); }); - describe('deleteOne/deleteMany', function() { - it('handles deleteOne', async function() { + describe('deleteOne/deleteMany', function () { + it('handles deleteOne', async function () { const M = db.model('Person', new Schema({ name: 'String' })); - await M.deleteMany({}); await M.create([{ name: 'Eddard Stark' }, { name: 'Robb Stark' }]); @@ -1157,10 +1274,9 @@ describe('Query', function() { assert.equal(count, 1); }); - it('handles deleteMany', async function() { + it('handles deleteMany', async function () { const M = db.model('Person', new Schema({ name: 'String' })); - await M.deleteMany({}); await M.create([{ name: 'Eddard Stark' }, { name: 'Robb Stark' }]); @@ -1171,36 +1287,41 @@ describe('Query', function() { }); }); - describe('remove', function() { - it('handles cast errors async', function(done) { + describe('remove', function () { + it('handles cast errors async', function (done) { const Product = db.model('Product', productSchema); - assert.doesNotThrow(function() { - Product.where({ numbers: [[[]]] }).deleteMany(function(err) { + assert.doesNotThrow(function () { + Product.where({ numbers: [[[]]] }).deleteMany(function (err) { assert.ok(err); done(); }); }); }); - it('supports a single conditions arg', function(done) { + it('supports a single conditions arg', function (done) { const Product = db.model('Product', productSchema); - Product.create({ strings: ['remove-single-condition'] }).then(function() { - const q = Product.where().deleteMany({ strings: 'remove-single-condition' }); - assert.ok(q instanceof mongoose.Query); - done(); - }, done); + Product.create({ strings: ['remove-single-condition'] }).then( + function () { + const q = Product.where().deleteMany({ + strings: 'remove-single-condition', + }); + assert.ok(q instanceof mongoose.Query); + done(); + }, + done + ); }); - it('supports a single callback arg', function(done) { + it('supports a single callback arg', function (done) { const Product = db.model('Product', productSchema); const val = 'remove-single-callback'; - Product.create({ strings: [val] }).then(function() { - Product.where({ strings: val }).deleteMany(function(err) { + Product.create({ strings: [val] }).then(function () { + Product.where({ strings: val }).deleteMany(function (err) { assert.ifError(err); - Product.findOne({ strings: val }, function(err, doc) { + Product.findOne({ strings: val }, function (err, doc) { assert.ifError(err); assert.ok(!doc); done(); @@ -1209,14 +1330,14 @@ describe('Query', function() { }, done); }); - it('supports conditions and callback args', function(done) { + it('supports conditions and callback args', function (done) { const Product = db.model('Product', productSchema); const val = 'remove-cond-and-callback'; - Product.create({ strings: [val] }).then(function() { - Product.where().deleteMany({ strings: val }, function(err) { + Product.create({ strings: [val] }).then(function () { + Product.where().deleteMany({ strings: val }, function (err) { assert.ifError(err); - Product.findOne({ strings: val }, function(err, doc) { + Product.findOne({ strings: val }, function (err, doc) { assert.ifError(err); assert.ok(!doc); done(); @@ -1226,41 +1347,44 @@ describe('Query', function() { }); }); - describe('querying/updating with model instance containing embedded docs should work (#454)', function() { - it('works', function(done) { + describe('querying/updating with model instance containing embedded docs should work (#454)', function () { + it('works', function (done) { const Product = db.model('Product', productSchema); const proddoc = { comments: [{ text: 'hello' }] }; const prod2doc = { comments: [{ text: 'goodbye' }] }; const prod = new Product(proddoc); - prod.save(function(err) { + prod.save(function (err) { assert.ifError(err); - Product.findOne({ _id: prod._id }, function(err, product) { + Product.findOne({ _id: prod._id }, function (err, product) { assert.ifError(err); assert.equal(product.comments.length, 1); assert.equal(product.comments[0].text, 'hello'); - Product.updateOne({ _id: prod._id }, prod2doc, function(err) { + Product.updateOne({ _id: prod._id }, prod2doc, function (err) { assert.ifError(err); - Product.collection.findOne({ _id: product._id }, function(err, doc) { - assert.ifError(err); - assert.equal(doc.comments.length, 1); - // ensure hidden private props were not saved to db - assert.ok(!doc.comments[0].hasOwnProperty('parentArry')); - assert.equal(doc.comments[0].text, 'goodbye'); - done(); - }); + Product.collection.findOne( + { _id: product._id }, + function (err, doc) { + assert.ifError(err); + assert.equal(doc.comments.length, 1); + // ensure hidden private props were not saved to db + assert.ok(!doc.comments[0].hasOwnProperty('parentArry')); + assert.equal(doc.comments[0].text, 'goodbye'); + done(); + } + ); }); }); }); }); }); - describe('optionsForExec', function() { - it('should retain key order', function(done) { + describe('optionsForExec', function () { + it('should retain key order', function (done) { // this is important for query hints const hint = { x: 1, y: 1, z: 1 }; const a = JSON.stringify({ hint: hint }); @@ -1273,7 +1397,7 @@ describe('Query', function() { done(); }); - it('applies schema-level writeConcern option', function(done) { + it('applies schema-level writeConcern option', function (done) { const q = new Query(); q.j(true); @@ -1281,20 +1405,20 @@ describe('Query', function() { const options = q._optionsForExec({ schema: { options: { - writeConcern: { w: 'majority' } - } - } + writeConcern: { w: 'majority' }, + }, + }, }); assert.deepEqual(options, { writeConcern: { w: 'majority', - j: true - } + j: true, + }, }); done(); }); - it('session() (gh-6663)', function(done) { + it('session() (gh-6663)', function (done) { const q = new Query(); const fakeSession = 'foo'; @@ -1302,7 +1426,7 @@ describe('Query', function() { const options = q._optionsForExec(); assert.deepEqual(options, { - session: fakeSession + session: fakeSession, }); done(); }); @@ -1310,9 +1434,9 @@ describe('Query', function() { // Advanced Query options - describe('options', function() { - describe('maxscan', function() { - it('works', function(done) { + describe('options', function () { + describe('maxscan', function () { + it('works', function (done) { const query = new Query({}); query.maxscan(100); assert.equal(query.options.maxScan, 100); @@ -1320,8 +1444,8 @@ describe('Query', function() { }); }); - describe('slaveOk', function() { - it('works', function(done) { + describe('slaveOk', function () { + it('works', function (done) { let query = new Query({}); query.slaveOk(); assert.equal(query.options.slaveOk, true); @@ -1337,8 +1461,8 @@ describe('Query', function() { }); }); - describe('tailable', function() { - it('works', function(done) { + describe('tailable', function () { + it('works', function (done) { let query = new Query({}); query.tailable(); assert.equal(query.options.tailable, true); @@ -1352,7 +1476,7 @@ describe('Query', function() { assert.equal(query.options.tailable, false); done(); }); - it('supports passing the `awaitData` option', function(done) { + it('supports passing the `awaitData` option', function (done) { const query = new Query({}); query.tailable({ awaitData: true }); assert.equal(query.options.tailable, true); @@ -1361,8 +1485,8 @@ describe('Query', function() { }); }); - describe('comment', function() { - it('works', function(done) { + describe('comment', function () { + it('works', function (done) { const query = new Query(); assert.equal(typeof query.comment, 'function'); assert.equal(query.comment('Lowpass is more fun'), query); @@ -1371,11 +1495,14 @@ describe('Query', function() { }); }); - describe('hint', function() { - it('works', function(done) { + describe('hint', function () { + it('works', function (done) { const query2 = new Query({}); query2.hint({ indexAttributeA: 1, indexAttributeB: -1 }); - assert.deepEqual(query2.options.hint, { indexAttributeA: 1, indexAttributeB: -1 }); + assert.deepEqual(query2.options.hint, { + indexAttributeA: 1, + indexAttributeB: -1, + }); const query3 = new Query({}); query3.hint('indexAttributeA_1'); @@ -1385,8 +1512,8 @@ describe('Query', function() { }); }); - describe('snapshot', function() { - it('works', function(done) { + describe('snapshot', function () { + it('works', function (done) { const query = new Query({}); query.snapshot(true); assert.equal(query.options.snapshot, true); @@ -1394,8 +1521,8 @@ describe('Query', function() { }); }); - describe('batchSize', function() { - it('works', function(done) { + describe('batchSize', function () { + it('works', function (done) { const query = new Query({}); query.batchSize(10); assert.equal(query.options.batchSize, 10); @@ -1403,11 +1530,11 @@ describe('Query', function() { }); }); - describe('read', function() { + describe('read', function () { const P = mongoose.mongo.ReadPreference; - describe('without tags', function() { - it('works', function(done) { + describe('without tags', function () { + it('works', function (done) { const query = new Query({}); query.read('primary'); assert.ok(query.options.readPreference instanceof P); @@ -1463,10 +1590,13 @@ describe('Query', function() { }); }); - describe('with tags', function() { - it('works', function(done) { + describe('with tags', function () { + it('works', function (done) { const query = new Query({}); - const tags = [{ dc: 'sf', s: 1 }, { dc: 'jp', s: 2 }]; + const tags = [ + { dc: 'sf', s: 1 }, + { dc: 'jp', s: 2 }, + ]; query.read('pp', tags); assert.ok(query.options.readPreference instanceof P); @@ -1481,36 +1611,39 @@ describe('Query', function() { }); }); - describe('inherits its models schema read option', function() { + describe('inherits its models schema read option', function () { let schema, M, called; - before(function() { + before(function () { schema = new Schema({}, { read: 'p' }); M = mongoose.model('schemaOptionReadPrefWithQuery', schema); }); - it('if not set in query', function(done) { + it('if not set in query', function (done) { const options = M.where()._optionsForExec(M); assert.ok(options.readPreference instanceof P); assert.equal(options.readPreference.mode, 'primary'); done(); }); - it('if set in query', function(done) { + it('if set in query', function (done) { const options = M.where().read('s')._optionsForExec(M); assert.ok(options.readPreference instanceof P); assert.equal(options.readPreference.mode, 'secondary'); done(); }); - it('and sends it though the driver', function(done) { - const options = { read: 'secondary', writeConcern: { w: 'majority' } }; + it('and sends it though the driver', function (done) { + const options = { + read: 'secondary', + writeConcern: { w: 'majority' }, + }; const schema = new Schema({ name: String }, options); const M = db.model('Test', schema); const q = M.find(); // stub the internal query options call const getopts = q._optionsForExec; - q._optionsForExec = function(model) { + q._optionsForExec = function (model) { q._optionsForExec = getopts; const ret = getopts.call(this, model); @@ -1523,7 +1656,7 @@ describe('Query', function() { return ret; }; - q.exec(function(err) { + q.exec(function (err) { if (err) { return done(err); } @@ -1535,8 +1668,8 @@ describe('Query', function() { }); }); - describe('setOptions', function() { - it('works', function(done) { + describe('setOptions', function () { + it('works', function (done) { const q = new Query(); q.setOptions({ thing: 'cat' }); q.setOptions({ populate: ['fans'] }); @@ -1549,7 +1682,11 @@ describe('Query', function() { q.setOptions({ read: ['s', [{ dc: 'eu' }]] }); assert.equal(q.options.thing, 'cat'); - assert.deepEqual(q._mongooseOptions.populate.fans, { path: 'fans', _docs: {}, _childDocs: [] }); + assert.deepEqual(q._mongooseOptions.populate.fans, { + path: 'fans', + _docs: {}, + _childDocs: [], + }); assert.equal(q.options.batchSize, 10); assert.equal(q.options.limit, 4); assert.equal(q.options.skip, 3); @@ -1564,27 +1701,33 @@ describe('Query', function() { const Product = db.model('Product', productSchema); Product.create( { numbers: [3, 4, 5] }, - { strings: 'hi there'.split(' ') }, function(err, doc1, doc2) { + { strings: 'hi there'.split(' ') }, + function (err, doc1, doc2) { assert.ifError(err); - Product.find().setOptions({ limit: 1, sort: { _id: -1 }, read: 'n' }).exec(function(err, docs) { - assert.ifError(err); - assert.equal(docs.length, 1); - assert.equal(docs[0].id, doc2.id); - done(); - }); - }); + Product.find() + .setOptions({ limit: 1, sort: { _id: -1 }, read: 'n' }) + .exec(function (err, docs) { + assert.ifError(err); + assert.equal(docs.length, 1); + assert.equal(docs[0].id, doc2.id); + done(); + }); + } + ); }); - it('populate as array in options (gh-4446)', function(done) { + it('populate as array in options (gh-4446)', function (done) { const q = new Query(); q.setOptions({ populate: [{ path: 'path1' }, { path: 'path2' }] }); - assert.deepEqual(Object.keys(q._mongooseOptions.populate), - ['path1', 'path2']); + assert.deepEqual(Object.keys(q._mongooseOptions.populate), [ + 'path1', + 'path2', + ]); done(); }); }); - describe('getOptions', function() { + describe('getOptions', function () { const q = new Query(); q.limit(10); q.setOptions({ maxTimeMS: 1000 }); @@ -1595,9 +1738,9 @@ describe('Query', function() { assert.strictEqual(opts.maxTimeMS, 1000); }); - describe('bug fixes', function() { - describe('collations', function() { - before(async function() { + describe('bug fixes', function () { + describe('collations', function () { + before(async function () { const _this = this; const version = await start.mongodVersion(); @@ -1607,52 +1750,57 @@ describe('Query', function() { } }); - it('collation support (gh-4839)', function(done) { + it('collation support (gh-4839)', function (done) { const schema = new Schema({ - name: String + name: String, }); const MyModel = db.model('Test', schema); const collation = { locale: 'en_US', strength: 1 }; - MyModel.create([{ name: 'a' }, { name: 'A' }]). - then(function() { + MyModel.create([{ name: 'a' }, { name: 'A' }]) + .then(function () { return MyModel.find({ name: 'a' }).collation(collation); - }). - then(function(docs) { + }) + .then(function (docs) { assert.equal(docs.length, 2); return MyModel.find({ name: 'a' }, null, { collation: collation }); - }). - then(function(docs) { + }) + .then(function (docs) { assert.equal(docs.length, 2); - return MyModel.find({ name: 'a' }, null, { collation: collation }). - sort({ _id: -1 }). - cursor(). - next(); - }). - then(function(doc) { + return MyModel.find({ name: 'a' }, null, { collation: collation }) + .sort({ _id: -1 }) + .cursor() + .next(); + }) + .then(function (doc) { assert.equal(doc.name, 'A'); return MyModel.find({ name: 'a' }); - }). - then(function(docs) { + }) + .then(function (docs) { assert.equal(docs.length, 1); done(); - }). - catch(done); + }) + .catch(done); }); - it('set on schema (gh-5295)', async function() { - - await db.db.collection('tests').drop().catch(err => { - if (err.message === 'ns not found') { - return; - } - throw err; - }); + it('set on schema (gh-5295)', async function () { + await db.db + .collection('tests') + .drop() + .catch((err) => { + if (err.message === 'ns not found') { + return; + } + throw err; + }); - const schema = new Schema({ - name: String - }, { collation: { locale: 'en_US', strength: 1 } }); + const schema = new Schema( + { + name: String, + }, + { collation: { locale: 'en_US', strength: 1 } } + ); const MyModel = db.model('Test', schema, 'tests'); @@ -1664,144 +1812,182 @@ describe('Query', function() { }); }); - describe('gh-1950', function() { - it.skip('ignores sort when passed to count', function(done) { + describe('gh-1950', function () { + it.skip('ignores sort when passed to count', function (done) { const Product = db.model('Product', productSchema); - Product.find().sort({ _id: 1 }).count({}).exec(function(error) { - assert.ifError(error); - done(); - }); + Product.find() + .sort({ _id: 1 }) + .count({}) + .exec(function (error) { + assert.ifError(error); + done(); + }); }); - it('ignores sort when passed to countDocuments', function() { + it('ignores sort when passed to countDocuments', function () { const Product = db.model('Product', productSchema); - return Product.create({}). - then(() => Product.find().sort({ _id: 1 }).countDocuments({}).exec()); + return Product.create({}).then(() => + Product.find().sort({ _id: 1 }).countDocuments({}).exec() + ); }); - it.skip('ignores count when passed to sort', function(done) { + it.skip('ignores count when passed to sort', function (done) { const Product = db.model('Product', productSchema); - Product.find().count({}).sort({ _id: 1 }).exec(function(error) { - assert.ifError(error); - done(); - }); + Product.find() + .count({}) + .sort({ _id: 1 }) + .exec(function (error) { + assert.ifError(error); + done(); + }); }); }); - it('excludes _id when select false and inclusive mode (gh-3010)', function(done) { + it('excludes _id when select false and inclusive mode (gh-3010)', function (done) { const User = db.model('User', { _id: { select: false, type: Schema.Types.ObjectId, - default: () => new mongoose.Types.ObjectId() + default: () => new mongoose.Types.ObjectId(), }, - username: String + username: String, }); - User.create({ username: 'Val' }, function(error, user) { + User.create({ username: 'Val' }, function (error, user) { assert.ifError(error); - User.find({ _id: user._id }).select('username').exec(function(error, users) { - assert.ifError(error); - assert.equal(users.length, 1); - assert.ok(!users[0]._id); - assert.equal(users[0].username, 'Val'); - done(); - }); + User.find({ _id: user._id }) + .select('username') + .exec(function (error, users) { + assert.ifError(error); + assert.equal(users.length, 1); + assert.ok(!users[0]._id); + assert.equal(users[0].username, 'Val'); + done(); + }); }); }); - it('doesnt reverse key order for update docs (gh-3215)', function(done) { + it('doesnt reverse key order for update docs (gh-3215)', function (done) { const Test = db.model('Test', { - arr: [{ date: Date, value: Number }] + arr: [{ date: Date, value: Number }], }); - const q = Test.updateOne({}, { - $push: { - arr: { - $each: [{ date: new Date(), value: 1 }], - $sort: { value: -1, date: -1 } - } + const q = Test.updateOne( + {}, + { + $push: { + arr: { + $each: [{ date: new Date(), value: 1 }], + $sort: { value: -1, date: -1 }, + }, + }, } - }); + ); - assert.deepEqual(Object.keys(q.getUpdate().$push.arr.$sort), - ['value', 'date']); + assert.deepEqual(Object.keys(q.getUpdate().$push.arr.$sort), [ + 'value', + 'date', + ]); done(); }); - it('timestamps with $each (gh-4805)', function(done) { + it('timestamps with $each (gh-4805)', function (done) { const nestedSchema = new Schema({ value: Number }, { timestamps: true }); - const Test = db.model('Test', new Schema({ - arr: [nestedSchema] - }, { timestamps: true })); + const Test = db.model( + 'Test', + new Schema( + { + arr: [nestedSchema], + }, + { timestamps: true } + ) + ); - Test.updateOne({}, { - $push: { - arr: { - $each: [{ value: 1 }] - } + Test.updateOne( + {}, + { + $push: { + arr: { + $each: [{ value: 1 }], + }, + }, } - }).exec(function(error) { + ).exec(function (error) { assert.ifError(error); done(); }); }); - it.skip('allows sort with count (gh-3914)', function(done) { + it.skip('allows sort with count (gh-3914)', function (done) { const Post = db.model('BlogPost', { - title: String + title: String, }); - Post.count({}).sort({ title: 1 }).exec(function(error, count) { - assert.ifError(error); - assert.strictEqual(count, 0); - done(); - }); + Post.count({}) + .sort({ title: 1 }) + .exec(function (error, count) { + assert.ifError(error); + assert.strictEqual(count, 0); + done(); + }); }); - it.skip('allows sort with select (gh-3914)', function(done) { + it.skip('allows sort with select (gh-3914)', function (done) { const Post = db.model('BlogPost', { - title: String + title: String, }); - Post.count({}).select({ _id: 0 }).exec(function(error, count) { - assert.ifError(error); - assert.strictEqual(count, 0); - done(); - }); + Post.count({}) + .select({ _id: 0 }) + .exec(function (error, count) { + assert.ifError(error); + assert.strictEqual(count, 0); + done(); + }); }); - it('handles nested $ (gh-3265)', function(done) { + it('handles nested $ (gh-3265)', function (done) { const Post = db.model('BlogPost', { title: String, - answers: [{ - details: String, - stats: { - votes: Number, - count: Number - } - }] + answers: [ + { + details: String, + stats: { + votes: Number, + count: Number, + }, + }, + ], }); - const answersUpdate = { details: 'blah', stats: { votes: 1, count: '3' } }; + const answersUpdate = { + details: 'blah', + stats: { votes: 1, count: '3' }, + }; const q = Post.updateOne( { 'answers._id': '507f1f77bcf86cd799439011' }, - { $set: { 'answers.$': answersUpdate } }); + { $set: { 'answers.$': answersUpdate } } + ); - assert.deepEqual(q.getUpdate().$set['answers.$'].stats, - { votes: 1, count: 3 }); + assert.deepEqual(q.getUpdate().$set['answers.$'].stats, { + votes: 1, + count: 3, + }); done(); }); - it('$geoWithin with single nested schemas (gh-4044)', function(done) { - const locationSchema = new Schema({ - type: { type: String }, - coordinates: [] - }, { _id: false }); + it('$geoWithin with single nested schemas (gh-4044)', function (done) { + const locationSchema = new Schema( + { + type: { type: String }, + coordinates: [], + }, + { _id: false } + ); const schema = new Schema({ title: String, - location: { type: locationSchema, required: true } + location: { type: locationSchema, required: true }, }); schema.index({ location: '2dsphere' }); @@ -1812,29 +1998,37 @@ describe('Query', function() { $geoWithin: { $geometry: { type: 'Polygon', - coordinates: [[[-1, 0], [-1, 3], [4, 3], [4, 0], [-1, 0]]] - } - } - } + coordinates: [ + [ + [-1, 0], + [-1, 3], + [4, 3], + [4, 0], + [-1, 0], + ], + ], + }, + }, + }, }; - Model.find(query, function(error) { + Model.find(query, function (error) { assert.ifError(error); done(); }); }); - it('setDefaultsOnInsert with empty update (gh-3825)', function(done) { + it('setDefaultsOnInsert with empty update (gh-3825)', function (done) { const schema = new mongoose.Schema({ test: { type: Number, default: 8472 }, - name: String + name: String, }); const MyModel = db.model('Test', schema); const opts = { upsert: true }; - MyModel.updateOne({}, {}, opts, function(error) { + MyModel.updateOne({}, {}, opts, function (error) { assert.ifError(error); - MyModel.findOne({}, function(error, doc) { + MyModel.findOne({}, function (error, doc) { assert.ifError(error); assert.ok(doc); assert.strictEqual(doc.test, 8472); @@ -1844,46 +2038,48 @@ describe('Query', function() { }); }); - it('custom query methods (gh-3714)', function(done) { + it('custom query methods (gh-3714)', function (done) { const schema = new mongoose.Schema({ - name: String + name: String, }); - schema.query.byName = function(name) { + schema.query.byName = function (name) { return this.find({ name: name }); }; const MyModel = db.model('Test', schema); - MyModel.create({ name: 'Val' }, function(error) { + MyModel.create({ name: 'Val' }, function (error) { assert.ifError(error); - MyModel.find().byName('Val').exec(function(error, docs) { - assert.ifError(error); - assert.equal(docs.length, 1); - assert.equal(docs[0].name, 'Val'); - done(); - }); + MyModel.find() + .byName('Val') + .exec(function (error, docs) { + assert.ifError(error); + assert.equal(docs.length, 1); + assert.equal(docs[0].name, 'Val'); + done(); + }); }); }); - it('string as input (gh-4378)', function(done) { + it('string as input (gh-4378)', function (done) { const schema = new mongoose.Schema({ - name: String + name: String, }); const MyModel = db.model('Test', schema); - MyModel.findOne('', function(error) { + MyModel.findOne('', function (error) { assert.ok(error); assert.equal(error.name, 'ObjectParameterError'); done(); }); }); - it('handles geoWithin with $center and mongoose object (gh-4419)', function(done) { + it('handles geoWithin with $center and mongoose object (gh-4419)', function (done) { const areaSchema = new Schema({ name: String, - circle: Array + circle: Array, }); const Area = db.model('Test', areaSchema); @@ -1893,38 +2089,38 @@ describe('Query', function() { type: { type: String, enum: ['Point'], - default: 'Point' + default: 'Point', }, - coordinates: { type: [Number] } - } + coordinates: { type: [Number] }, + }, }); placeSchema.index({ geometry: '2dsphere' }); const Place = db.model('Place', placeSchema); const tromso = new Area({ name: 'Tromso, Norway', - circle: [[18.89, 69.62], 10 / 3963.2] + circle: [[18.89, 69.62], 10 / 3963.2], }); - tromso.save(function(error) { + tromso.save(function (error) { assert.ifError(error); const airport = { name: 'Center', geometry: { type: 'Point', - coordinates: [18.895, 69.67] - } + coordinates: [18.895, 69.67], + }, }; - Place.create(airport, function(error) { + Place.create(airport, function (error) { assert.ifError(error); const q = { geometry: { $geoWithin: { - $centerSphere: tromso.circle - } - } + $centerSphere: tromso.circle, + }, + }, }; - Place.find(q).exec(function(error, docs) { + Place.find(q).exec(function (error, docs) { assert.ifError(error); assert.equal(docs.length, 1); assert.equal(docs[0].name, 'Center'); @@ -1934,9 +2130,9 @@ describe('Query', function() { }); }); - it('$not with objects (gh-4495)', function(done) { + it('$not with objects (gh-4495)', function (done) { const schema = new Schema({ - createdAt: Date + createdAt: Date, }); const M = db.model('Test', schema); @@ -1944,9 +2140,9 @@ describe('Query', function() { createdAt: { $not: { $gte: '2016/09/02 00:00:00', - $lte: '2016/09/02 23:59:59' - } - } + $lte: '2016/09/02 23:59:59', + }, + }, }); q._castConditions(); @@ -1955,13 +2151,13 @@ describe('Query', function() { done(); }); - it('geoIntersects with mongoose doc as coords (gh-4408)', function(done) { + it('geoIntersects with mongoose doc as coords (gh-4408)', function (done) { const lineStringSchema = new Schema({ name: String, geo: { type: { type: String, default: 'LineString' }, - coordinates: [[Number]] - } + coordinates: [[Number]], + }, }); const LineString = db.model('Test', lineStringSchema); @@ -1969,28 +2165,34 @@ describe('Query', function() { const ls = { name: 'test', geo: { - coordinates: [[14.59, 24.847], [28.477, 15.961]] - } + coordinates: [ + [14.59, 24.847], + [28.477, 15.961], + ], + }, }; const ls2 = { name: 'test2', geo: { - coordinates: [[27.528, 25.006], [14.063, 15.591]] - } + coordinates: [ + [27.528, 25.006], + [14.063, 15.591], + ], + }, }; - LineString.create(ls, ls2, function(error, ls1) { + LineString.create(ls, ls2, function (error, ls1) { assert.ifError(error); const query = { geo: { $geoIntersects: { $geometry: { type: 'LineString', - coordinates: ls1.geo.coordinates - } - } - } + coordinates: ls1.geo.coordinates, + }, + }, + }, }; - LineString.find(query, function(error, results) { + LineString.find(query, function (error, results) { assert.ifError(error); assert.equal(results.length, 2); done(); @@ -1998,23 +2200,22 @@ describe('Query', function() { }); }); - it('string with $not (gh-4592)', function(done) { + it('string with $not (gh-4592)', function (done) { const TestSchema = new Schema({ - test: String + test: String, }); const Test = db.model('Test', TestSchema); - Test.findOne({ test: { $not: /test/ } }, function(error) { + Test.findOne({ test: { $not: /test/ } }, function (error) { assert.ifError(error); done(); }); }); - it('does not cast undefined to null in mongoose (gh-6236)', async function() { - + it('does not cast undefined to null in mongoose (gh-6236)', async function () { const TestSchema = new Schema({ - test: String + test: String, }); const Test = db.model('Test', TestSchema); @@ -2029,46 +2230,49 @@ describe('Query', function() { assert.equal(res.length, 1); }); - it('runs query setters with _id field (gh-5351)', function(done) { + it('runs query setters with _id field (gh-5351)', function (done) { const testSchema = new Schema({ - val: { type: String } + val: { type: String }, }); const Test = db.model('Test', testSchema); - Test.create({ val: 'A string' }). - then(function() { + Test.create({ val: 'A string' }) + .then(function () { return Test.findOne({}); - }). - then(function(doc) { - return Test.findOneAndUpdate({ _id: doc._id }, { - $set: { - val: 'another string' - } - }, { new: true }); - }). - then(function(doc) { + }) + .then(function (doc) { + return Test.findOneAndUpdate( + { _id: doc._id }, + { + $set: { + val: 'another string', + }, + }, + { new: true } + ); + }) + .then(function (doc) { assert.ok(doc); assert.equal(doc.val, 'another string'); - }). - then(done). - catch(done); + }) + .then(done) + .catch(done); }); - it('runs setters if query field is an array (gh-6277)', async function() { + it('runs setters if query field is an array (gh-6277)', async function () { const setterCalled = []; const schema = new Schema({ strings: { type: [String], - set: v => { + set: (v) => { setterCalled.push(v); return v; - } - } + }, + }, }); const Model = db.model('Test', schema); - await Model.find({ strings: 'test' }); assert.equal(setterCalled.length, 0); @@ -2077,30 +2281,32 @@ describe('Query', function() { assert.deepEqual(setterCalled, [['test']]); }); - it('$exists under $not (gh-4933)', function(done) { + it('$exists under $not (gh-4933)', function (done) { const TestSchema = new Schema({ - test: String + test: String, }); const Test = db.model('Test', TestSchema); - Test.findOne({ test: { $not: { $exists: true } } }, function(error) { + Test.findOne({ test: { $not: { $exists: true } } }, function (error) { assert.ifError(error); done(); }); }); - it('geojson underneath array (gh-5467)', function(done) { + it('geojson underneath array (gh-5467)', function (done) { const storySchema = new Schema({ name: String, - gallery: [{ - src: String, - location: { - type: { type: String, enum: ['Point'] }, - coordinates: { type: [Number], default: void 0 } + gallery: [ + { + src: String, + location: { + type: { type: String, enum: ['Point'] }, + coordinates: { type: [Number], default: void 0 }, + }, + timestamp: Date, }, - timestamp: Date - }] + ], }); storySchema.index({ 'gallery.location': '2dsphere' }); @@ -2111,73 +2317,83 @@ describe('Query', function() { $near: { $geometry: { type: 'Point', - coordinates: [51.53377166666667, -0.1197471666666667] + coordinates: [51.53377166666667, -0.1197471666666667], }, - $maxDistance: 500 - } - } + $maxDistance: 500, + }, + }, }; - Story.once('index', function(error) { + Story.once('index', function (error) { assert.ifError(error); - Story.updateOne(q, { name: 'test' }, { upsert: true }, function(error) { - assert.ifError(error); - done(); - }); + Story.updateOne( + q, + { name: 'test' }, + { upsert: true }, + function (error) { + assert.ifError(error); + done(); + } + ); }); }); - it('slice respects schema projections (gh-5450)', function(done) { + it('slice respects schema projections (gh-5450)', function (done) { const gameSchema = Schema({ name: String, developer: { type: String, - select: false + select: false, }, - arr: [Number] + arr: [Number], }); const Game = db.model('Test', gameSchema); - Game.create({ name: 'Mass Effect', developer: 'BioWare', arr: [1, 2, 3] }, function(error) { - assert.ifError(error); - Game.findOne({ name: 'Mass Effect' }).slice({ arr: 1 }).exec(function(error, doc) { + Game.create( + { name: 'Mass Effect', developer: 'BioWare', arr: [1, 2, 3] }, + function (error) { assert.ifError(error); - assert.equal(doc.name, 'Mass Effect'); - assert.deepEqual(doc.toObject().arr, [1]); - assert.ok(!doc.developer); - done(); - }); - }); + Game.findOne({ name: 'Mass Effect' }) + .slice({ arr: 1 }) + .exec(function (error, doc) { + assert.ifError(error); + assert.equal(doc.name, 'Mass Effect'); + assert.deepEqual(doc.toObject().arr, [1]); + assert.ok(!doc.developer); + done(); + }); + } + ); }); - it('overwrites when passing an object when path already set to primitive (gh-6097)', function() { + it('overwrites when passing an object when path already set to primitive (gh-6097)', function () { const schema = new mongoose.Schema({ status: String }); const Model = db.model('Test', schema); - return Model. - where({ status: 'approved' }). - where({ status: { $ne: 'delayed' } }); + return Model.where({ status: 'approved' }).where({ + status: { $ne: 'delayed' }, + }); }); - it('$exists for arrays and embedded docs (gh-4937)', function(done) { + it('$exists for arrays and embedded docs (gh-4937)', function (done) { const subSchema = new Schema({ - name: String + name: String, }); const TestSchema = new Schema({ test: [String], - sub: subSchema + sub: subSchema, }); const Test = db.model('Test', TestSchema); const q = { test: { $exists: true }, sub: { $exists: false } }; - Test.findOne(q, function(error) { + Test.findOne(q, function (error) { assert.ifError(error); done(); }); }); - it('report error in pre hook (gh-5520)', function(done) { + it('report error in pre hook (gh-5520)', function (done) { const TestSchema = new Schema({ name: String }); const ops = [ @@ -2189,11 +2405,11 @@ describe('Query', function() { 'replaceOne', 'update', 'updateOne', - 'updateMany' + 'updateMany', ]; - ops.forEach(function(op) { - TestSchema.pre(op, function(next) { + ops.forEach(function (op) { + TestSchema.pre(op, function (next) { this.error(new Error(op + ' error')); next(); }); @@ -2203,24 +2419,25 @@ describe('Query', function() { let numOps = ops.length; - ops.forEach(function(op) { - TestModel.find({}).updateOne({ name: 'test' })[op](function(error) { - assert.ok(error); - assert.equal(error.message, op + ' error'); - --numOps || done(); - }); + ops.forEach(function (op) { + TestModel.find({}) + .updateOne({ name: 'test' }) + [op](function (error) { + assert.ok(error); + assert.equal(error.message, op + ' error'); + --numOps || done(); + }); }); }); - it('cast error with custom error (gh-5520)', function(done) { + it('cast error with custom error (gh-5520)', function (done) { const TestSchema = new Schema({ name: Number }); const TestModel = db.model('Test', TestSchema); - TestModel. - find({ name: 'not a number' }). - error(new Error('woops')). - exec(function(error) { + TestModel.find({ name: 'not a number' }) + .error(new Error('woops')) + .exec(function (error) { assert.ok(error); // CastError check happens **after** `.error()` assert.equal(error.name, 'CastError'); @@ -2228,15 +2445,15 @@ describe('Query', function() { }); }); - it('change deleteOne to updateOne for soft deletes using $isDeleted (gh-4428)', function(done) { + it('change deleteOne to updateOne for soft deletes using $isDeleted (gh-4428)', function (done) { const schema = new mongoose.Schema({ name: String, - isDeleted: Boolean + isDeleted: Boolean, }); - schema.pre('remove', function(next) { + schema.pre('remove', function (next) { const _this = this; - this.constructor.updateOne({ isDeleted: true }, function(error) { + this.constructor.updateOne({ isDeleted: true }, function (error) { // Force mongoose to consider this doc as deleted. _this.$isDeleted(true); next(error); @@ -2245,11 +2462,11 @@ describe('Query', function() { const M = db.model('Test', schema); - M.create({ name: 'test' }, function(error, doc) { + M.create({ name: 'test' }, function (error, doc) { assert.ifError(error); - doc.remove(function(error) { + doc.remove(function (error) { assert.ifError(error); - M.findById(doc._id, function(error, doc) { + M.findById(doc._id, function (error, doc) { assert.ifError(error); assert.ok(doc); assert.equal(doc.isDeleted, true); @@ -2259,26 +2476,29 @@ describe('Query', function() { }); }); - it('child schema with select: false in multiple paths (gh-5603)', function(done) { - const ChildSchema = new mongoose.Schema({ - field: { - type: String, - select: false + it('child schema with select: false in multiple paths (gh-5603)', function (done) { + const ChildSchema = new mongoose.Schema( + { + field: { + type: String, + select: false, + }, + _id: false, }, - _id: false - }, { id: false }); + { id: false } + ); const ParentSchema = new mongoose.Schema({ child: ChildSchema, - child2: ChildSchema + child2: ChildSchema, }); const Parent = db.model('Parent', ParentSchema); const ogParent = new Parent(); ogParent.child = { field: 'test' }; ogParent.child2 = { field: 'test' }; - ogParent.save(function(error) { + ogParent.save(function (error) { assert.ifError(error); - Parent.findById(ogParent._id).exec(function(error, doc) { + Parent.findById(ogParent._id).exec(function (error, doc) { assert.ifError(error); assert.ok(!doc.child.field); assert.ok(!doc.child2.field); @@ -2287,12 +2507,12 @@ describe('Query', function() { }); }); - it('errors in post init (gh-5592)', function(done) { + it('errors in post init (gh-5592)', function (done) { const TestSchema = new Schema(); let count = 0; - TestSchema.post('init', function() { - throw new Error('Failed! ' + (count++)); + TestSchema.post('init', function () { + throw new Error('Failed! ' + count++); }); const TestModel = db.model('Test', TestSchema); @@ -2302,9 +2522,9 @@ describe('Query', function() { docs.push({}); } - TestModel.create(docs, function(error) { + TestModel.create(docs, function (error) { assert.ifError(error); - TestModel.find({}, function(error) { + TestModel.find({}, function (error) { assert.ok(error); assert.equal(error.message, 'Failed! 0'); assert.equal(count, 10); @@ -2313,32 +2533,32 @@ describe('Query', function() { }); }); - it('with non-object args (gh-1698)', function(done) { + it('with non-object args (gh-1698)', function (done) { const schema = new mongoose.Schema({ - email: String + email: String, }); const M = db.model('Test', schema); - M.find(42, function(error) { + M.find(42, function (error) { assert.ok(error); assert.equal(error.name, 'ObjectParameterError'); done(); }); }); - describe('throw', function() { + describe('throw', function () { let listeners; - beforeEach(function() { + beforeEach(function () { listeners = process.listeners('uncaughtException'); process.removeAllListeners('uncaughtException'); }); - afterEach(function() { + afterEach(function () { process.on('uncaughtException', listeners[0]); }); - it('throw on sync exceptions in callbacks (gh-6178)', function(done) { + it('throw on sync exceptions in callbacks (gh-6178)', function (done) { // Deno doesn't support 'uncaughtException', so there's no way to test this in Deno // without starting a separate process. // See: https://stackoverflow.com/questions/64871554/deno-how-to-handle-exceptions @@ -2349,36 +2569,37 @@ describe('Query', function() { const schema = new Schema({}); const Test = db.model('Test', schema); - process.once('uncaughtException', err => { + process.once('uncaughtException', (err) => { assert.equal(err.message, 'Oops!'); done(); }); - Test.find({}, function() { throw new Error('Oops!'); }); + Test.find({}, function () { + throw new Error('Oops!'); + }); }); }); - it.skip('set overwrite after update() (gh-4740)', async function() { + it.skip('set overwrite after update() (gh-4740)', async function () { const schema = new Schema({ name: String, age: Number }); const User = db.model('User', schema); - await User.create({ name: 'Bar', age: 29 }); - await User.where({ name: 'Bar' }). - update({ name: 'Baz' }). - setOptions({ overwrite: true }); + await User.where({ name: 'Bar' }) + .update({ name: 'Baz' }) + .setOptions({ overwrite: true }); const doc = await User.findOne(); assert.equal(doc.name, 'Baz'); assert.ok(!doc.age); }); - it('queries with BSON overflow (gh-5812)', function(done) { + it('queries with BSON overflow (gh-5812)', function (done) { this.timeout(10000); const schema = new mongoose.Schema({ - email: String + email: String, }); const model = db.model('Test', schema); @@ -2388,20 +2609,22 @@ describe('Query', function() { bigData[i] = 'test1234567890'; } - model.find({ email: { $in: bigData } }).lean(). - then(function() { + model + .find({ email: { $in: bigData } }) + .lean() + .then(function () { done(new Error('Expected an error')); - }). - catch(function(error) { + }) + .catch(function (error) { assert.ok(error); assert.ok(error.message !== 'Expected error'); done(); }); }); - it('consistently return query when callback specified (gh-6271)', function(done) { + it('consistently return query when callback specified (gh-6271)', function (done) { const schema = new mongoose.Schema({ - n: Number + n: Number, }); const Model = db.model('Test', schema); @@ -2409,17 +2632,21 @@ describe('Query', function() { Model.create({ n: 0 }, (err, doc) => { assert.ifError(err); - const updateQuery = Model.findOneAndUpdate({ _id: doc._id }, { $inc: { n: 1 } }, { new: true }, (err, doc) => { - assert.ifError(err); - assert.equal(doc.n, 1); - done(); - }); + const updateQuery = Model.findOneAndUpdate( + { _id: doc._id }, + { $inc: { n: 1 } }, + { new: true }, + (err, doc) => { + assert.ifError(err); + assert.equal(doc.n, 1); + done(); + } + ); assert.ok(updateQuery instanceof Query); }); }); - it('explain() (gh-6625)', async function() { - + it('explain() (gh-6625)', async function () { const schema = new mongoose.Schema({ n: Number }); const Model = db.model('Test', schema); @@ -2436,25 +2663,36 @@ describe('Query', function() { assert.equal(res[0].n, 42); }); - it('cast embedded discriminators with dot notation (gh-6027)', async function() { + it('cast embedded discriminators with dot notation (gh-6027)', async function () { + const ownerSchema = new Schema( + { + _id: false, + }, + { + discriminatorKey: 'type', + } + ); - const ownerSchema = new Schema({ - _id: false - }, { - discriminatorKey: 'type' - }); + const userOwnerSchema = new Schema( + { + id: { type: Schema.Types.ObjectId, required: true }, + }, + { _id: false } + ); - const userOwnerSchema = new Schema({ - id: { type: Schema.Types.ObjectId, required: true } - }, { _id: false }); - - const tagOwnerSchema = new Schema({ - id: { type: String, required: true } - }, { _id: false }); + const tagOwnerSchema = new Schema( + { + id: { type: String, required: true }, + }, + { _id: false } + ); - const activitySchema = new Schema({ - owner: { type: ownerSchema, required: true } - }, { _id: false }); + const activitySchema = new Schema( + { + owner: { type: ownerSchema, required: true }, + }, + { _id: false } + ); activitySchema.path('owner').discriminator('user', userOwnerSchema); activitySchema.path('owner').discriminator('tag', tagOwnerSchema); @@ -2465,44 +2703,55 @@ describe('Query', function() { { owner: { id: '5a042f742a91c1db447534d5', - type: 'user' - } + type: 'user', + }, }, { owner: { id: 'asdf', - type: 'tag' - } - } + type: 'tag', + }, + }, ]); const activity = await Activity.findOne({ 'owner.type': 'user', - 'owner.id': '5a042f742a91c1db447534d5' + 'owner.id': '5a042f742a91c1db447534d5', }); assert.ok(activity); assert.equal(activity.owner.type, 'user'); }); - it('cast embedded discriminators with embedded obj (gh-6027)', async function() { - - const ownerSchema = new Schema({ - _id: false - }, { - discriminatorKey: 'type' - }); + it('cast embedded discriminators with embedded obj (gh-6027)', async function () { + const ownerSchema = new Schema( + { + _id: false, + }, + { + discriminatorKey: 'type', + } + ); - const userOwnerSchema = new Schema({ - id: { type: Schema.Types.ObjectId, required: true } - }, { _id: false }); + const userOwnerSchema = new Schema( + { + id: { type: Schema.Types.ObjectId, required: true }, + }, + { _id: false } + ); - const tagOwnerSchema = new Schema({ - id: { type: String, required: true } - }, { _id: false }); + const tagOwnerSchema = new Schema( + { + id: { type: String, required: true }, + }, + { _id: false } + ); - const activitySchema = new Schema({ - owner: { type: ownerSchema, required: true } - }, { _id: false }); + const activitySchema = new Schema( + { + owner: { type: ownerSchema, required: true }, + }, + { _id: false } + ); activitySchema.path('owner').discriminator('user', userOwnerSchema); activitySchema.path('owner').discriminator('tag', tagOwnerSchema); @@ -2513,36 +2762,44 @@ describe('Query', function() { { owner: { id: '5a042f742a91c1db447534d5', - type: 'user' - } + type: 'user', + }, }, { owner: { id: 'asdf', - type: 'tag' - } - } + type: 'tag', + }, + }, ]); const activity = await Activity.findOne({ owner: { type: 'user', - id: '5a042f742a91c1db447534d5' - } + id: '5a042f742a91c1db447534d5', + }, }); assert.ok(activity); assert.equal(activity.owner.type, 'user'); }); - it('cast embedded discriminators with $elemMatch discriminator key (gh-7449)', async function() { - const ListingLineSchema = new Schema({ - sellerId: Number - }, { strictQuery: false }); + it('cast embedded discriminators with $elemMatch discriminator key (gh-7449)', async function () { + const ListingLineSchema = new Schema( + { + sellerId: Number, + }, + { strictQuery: false } + ); const OrderSchema = new Schema({ - lines: [new Schema({ - amount: Number - }, { discriminatorKey: 'kind', strictQuery: false })] + lines: [ + new Schema( + { + amount: Number, + }, + { discriminatorKey: 'kind', strictQuery: false } + ), + ], }); OrderSchema.path('lines').discriminator('listing', ListingLineSchema); @@ -2552,27 +2809,27 @@ describe('Query', function() { await Order.create({ lines: { kind: 'listing', sellerId: 42 } }); let count = await Order.countDocuments({ - lines: { $elemMatch: { kind: 'listing', sellerId: '42' } } + lines: { $elemMatch: { kind: 'listing', sellerId: '42' } }, }); assert.strictEqual(count, 1); count = await Order.countDocuments({ - lines: { $elemMatch: { sellerId: '42' } } + lines: { $elemMatch: { sellerId: '42' } }, }); assert.strictEqual(count, 0); }); - it('handles geoWithin with mongoose docs (gh-4392)', async function() { + it('handles geoWithin with mongoose docs (gh-4392)', async function () { const areaSchema = new Schema({ name: { type: String }, loc: { type: { type: String, enum: ['Polygon'], - default: 'Polygon' + default: 'Polygon', }, - coordinates: [[[Number]]] - } + coordinates: [[[Number]]], + }, }); const Area = db.model('Test', areaSchema); @@ -2582,109 +2839,112 @@ describe('Query', function() { type: { type: String, enum: ['Point'], - default: 'Point' + default: 'Point', }, - coordinates: { type: [Number] } + coordinates: { type: [Number] }, }, properties: { - temperature: { type: Number } - } + temperature: { type: Number }, + }, }); observationSchema.index({ geometry: '2dsphere' }); const Observation = db.model('Test1', observationSchema); await Observation.init(); - const tromso = new Area({ name: 'Tromso, Norway', loc: { type: 'Polygon', - coordinates: [[ - [18.89, 69.62], - [18.89, 69.72], - [19.03, 69.72], - [19.03, 69.62], - [18.89, 69.62] - ]] - } + coordinates: [ + [ + [18.89, 69.62], + [18.89, 69.72], + [19.03, 69.72], + [19.03, 69.62], + [18.89, 69.62], + ], + ], + }, }); await tromso.save(); const observation = { geometry: { type: 'Point', - coordinates: [18.895, 69.67] - } + coordinates: [18.895, 69.67], + }, }; await Observation.create(observation); - - const docs = await Observation. - find(). - where('geometry').within().geometry(tromso.loc). - exec(); + const docs = await Observation.find() + .where('geometry') + .within() + .geometry(tromso.loc) + .exec(); assert.equal(docs.length, 1); }); }); - describe('handles falsy and object projections with defaults (gh-3256)', function() { + describe('handles falsy and object projections with defaults (gh-3256)', function () { let MyModel; - before(function() { + before(function () { const PersonSchema = new Schema({ name: String, lastName: String, dependents: [String], - salary: { type: Number, default: 25000 } + salary: { type: Number, default: 25000 }, }); db.deleteModel(/Person/); MyModel = db.model('Person', PersonSchema); }); - beforeEach(async function() { + beforeEach(async function () { await MyModel.collection.insertOne({ name: 'John', lastName: 'Doe', - dependents: ['Jake', 'Jill', 'Jane'] + dependents: ['Jake', 'Jill', 'Jane'], }); }); - it('falsy projection', function(done) { - MyModel.findOne({ name: 'John' }, { lastName: false }). - exec(function(error, person) { - assert.ifError(error); - assert.equal(person.salary, 25000); - done(); - }); - }); - - it('slice projection', function(done) { - MyModel.findOne({ name: 'John' }, { dependents: { $slice: 1 } }).exec(function(error, person) { + it('falsy projection', function (done) { + MyModel.findOne({ name: 'John' }, { lastName: false }).exec(function ( + error, + person + ) { assert.ifError(error); assert.equal(person.salary, 25000); done(); }); }); - it('empty projection', function(done) { - MyModel.findOne({ name: 'John' }, {}). - exec(function(error, person) { + it('slice projection', function (done) { + MyModel.findOne({ name: 'John' }, { dependents: { $slice: 1 } }).exec( + function (error, person) { assert.ifError(error); assert.equal(person.salary, 25000); done(); - }); + } + ); }); - }); - describe('count', function() { - it('calls utils.toObject on conditions (gh-6323)', async function() { + it('empty projection', function (done) { + MyModel.findOne({ name: 'John' }, {}).exec(function (error, person) { + assert.ifError(error); + assert.equal(person.salary, 25000); + done(); + }); + }); + }); + describe('count', function () { + it('calls utils.toObject on conditions (gh-6323)', async function () { const priceSchema = new Schema({ key: String, - price: Number + price: Number, }); const Model = db.model('Test', priceSchema); @@ -2711,8 +2971,8 @@ describe('Query', function() { }); }); - describe('setQuery', function() { - it('replaces existing query with new value (gh-6854)', function() { + describe('setQuery', function () { + it('replaces existing query with new value (gh-6854)', function () { const q = new Query({}); q.where('userName').exists(); q.setQuery({ a: 1 }); @@ -2720,13 +2980,12 @@ describe('Query', function() { }); }); - it('map (gh-7142)', async function() { + it('map (gh-7142)', async function () { const Model = db.model('Test', new Schema({ name: String })); - await Model.create({ name: 'test' }); const now = new Date(); - const res = await Model.findOne().transform(res => { + const res = await Model.findOne().transform((res) => { res.loadedAt = now; return res; }); @@ -2734,20 +2993,19 @@ describe('Query', function() { assert.equal(res.loadedAt, now); }); - describe('orFail (gh-6841)', function() { + describe('orFail (gh-6841)', function () { let Model; - before(function() { + before(function () { db.deleteModel(/Test/); Model = db.model('Test', new Schema({ name: String })); }); - beforeEach(function() { + beforeEach(function () { return Model.deleteMany({}).then(() => Model.create({ name: 'Test' })); }); - it('find()', async function() { - + it('find()', async function () { let threw = false; try { await Model.find({ name: 'na' }).orFail(() => new Error('Oops!')); @@ -2763,8 +3021,7 @@ describe('Query', function() { assert.equal(res[0].name, 'Test'); }); - it('findOne()', async function() { - + it('findOne()', async function () { let threw = false; try { await Model.findOne({ name: 'na' }).orFail(() => new Error('Oops!')); @@ -2776,12 +3033,13 @@ describe('Query', function() { assert.ok(threw); // Shouldn't throw - const res = await Model.findOne({ name: 'Test' }).orFail(new Error('Oops')); + const res = await Model.findOne({ name: 'Test' }).orFail( + new Error('Oops') + ); assert.equal(res.name, 'Test'); }); - it('deleteMany()', async function() { - + it('deleteMany()', async function () { let threw = false; try { await Model.deleteMany({ name: 'na' }).orFail(new Error('Oops!')); @@ -2793,12 +3051,13 @@ describe('Query', function() { assert.ok(threw); // Shouldn't throw - const res = await Model.deleteMany({ name: 'Test' }).orFail(new Error('Oops')); + const res = await Model.deleteMany({ name: 'Test' }).orFail( + new Error('Oops') + ); assert.equal(res.deletedCount, 1); }); - it('deleteOne()', async function() { - + it('deleteOne()', async function () { let threw = false; try { await Model.deleteOne({ name: 'na' }).orFail(new Error('Oops!')); @@ -2810,12 +3069,13 @@ describe('Query', function() { assert.ok(threw); // Shouldn't throw - const res = await Model.deleteOne({ name: 'Test' }).orFail(new Error('Oops')); + const res = await Model.deleteOne({ name: 'Test' }).orFail( + new Error('Oops') + ); assert.equal(res.deletedCount, 1); }); - it('remove()', async function() { - + it('remove()', async function () { let threw = false; try { await Model.remove({ name: 'na' }).orFail(new Error('Oops!')); @@ -2827,14 +3087,18 @@ describe('Query', function() { assert.ok(threw); // Shouldn't throw - const res = await Model.remove({ name: 'Test' }).orFail(new Error('Oops')); + const res = await Model.remove({ name: 'Test' }).orFail( + new Error('Oops') + ); assert.equal(res.deletedCount, 1); }); - it('replaceOne()', async function() { + it('replaceOne()', async function () { let threw = false; try { - await Model.replaceOne({ name: 'na' }, { name: 'bar' }).orFail(new Error('Oops!')); + await Model.replaceOne({ name: 'na' }, { name: 'bar' }).orFail( + new Error('Oops!') + ); } catch (error) { assert.ok(error); assert.equal(error.message, 'Oops!'); @@ -2843,16 +3107,19 @@ describe('Query', function() { assert.ok(threw); // Shouldn't throw - const res = await Model.replaceOne({ name: 'Test' }, { name: 'bar' }).orFail(new Error('Oops')); + const res = await Model.replaceOne( + { name: 'Test' }, + { name: 'bar' } + ).orFail(new Error('Oops')); assert.equal(res.modifiedCount, 1); }); - it('update()', async function() { - + it('update()', async function () { let threw = false; try { - await Model.update({ name: 'na' }, { name: 'foo' }). - orFail(new Error('Oops!')); + await Model.update({ name: 'na' }, { name: 'foo' }).orFail( + new Error('Oops!') + ); } catch (error) { assert.ok(error); assert.equal(error.message, 'Oops!'); @@ -2861,16 +3128,18 @@ describe('Query', function() { assert.ok(threw); // Shouldn't throw - const res = await Model.update({}, { name: 'Test2' }).orFail(new Error('Oops')); + const res = await Model.update({}, { name: 'Test2' }).orFail( + new Error('Oops') + ); assert.equal(res.modifiedCount, 1); }); - it('updateMany()', async function() { - + it('updateMany()', async function () { let threw = false; try { - await Model.updateMany({ name: 'na' }, { name: 'foo' }). - orFail(new Error('Oops!')); + await Model.updateMany({ name: 'na' }, { name: 'foo' }).orFail( + new Error('Oops!') + ); } catch (error) { assert.ok(error); assert.equal(error.message, 'Oops!'); @@ -2879,16 +3148,18 @@ describe('Query', function() { assert.ok(threw); // Shouldn't throw - const res = await Model.updateMany({}, { name: 'Test2' }).orFail(new Error('Oops')); + const res = await Model.updateMany({}, { name: 'Test2' }).orFail( + new Error('Oops') + ); assert.equal(res.modifiedCount, 1); }); - it('updateOne()', async function() { - + it('updateOne()', async function () { let threw = false; try { - await Model.updateOne({ name: 'na' }, { name: 'foo' }). - orFail(new Error('Oops!')); + await Model.updateOne({ name: 'na' }, { name: 'foo' }).orFail( + new Error('Oops!') + ); } catch (error) { assert.ok(error); assert.equal(error.message, 'Oops!'); @@ -2897,16 +3168,18 @@ describe('Query', function() { assert.ok(threw); // Shouldn't throw - const res = await Model.updateOne({}, { name: 'Test2' }).orFail(new Error('Oops')); + const res = await Model.updateOne({}, { name: 'Test2' }).orFail( + new Error('Oops') + ); assert.equal(res.modifiedCount, 1); }); - it('findOneAndUpdate()', async function() { - + it('findOneAndUpdate()', async function () { let threw = false; try { - await Model.findOneAndUpdate({ name: 'na' }, { name: 'foo' }). - orFail(new Error('Oops!')); + await Model.findOneAndUpdate({ name: 'na' }, { name: 'foo' }).orFail( + new Error('Oops!') + ); } catch (error) { assert.ok(error); assert.equal(error.message, 'Oops!'); @@ -2915,16 +3188,16 @@ describe('Query', function() { assert.ok(threw); // Shouldn't throw - const res = await Model.findOneAndUpdate({}, { name: 'Test2' }).orFail(new Error('Oops')); + const res = await Model.findOneAndUpdate({}, { name: 'Test2' }).orFail( + new Error('Oops') + ); assert.equal(res.name, 'Test'); }); - it('findOneAndDelete()', async function() { - + it('findOneAndDelete()', async function () { let threw = false; try { - await Model.findOneAndDelete({ name: 'na' }). - orFail(new Error('Oops!')); + await Model.findOneAndDelete({ name: 'na' }).orFail(new Error('Oops!')); } catch (error) { assert.ok(error); assert.equal(error.message, 'Oops!'); @@ -2933,15 +3206,16 @@ describe('Query', function() { assert.ok(threw); // Shouldn't throw - const res = await Model.findOneAndDelete({ name: 'Test' }).orFail(new Error('Oops')); + const res = await Model.findOneAndDelete({ name: 'Test' }).orFail( + new Error('Oops') + ); assert.equal(res.name, 'Test'); }); - it('executes before post hooks (gh-7280)', async function() { - + it('executes before post hooks (gh-7280)', async function () { const schema = new Schema({ name: String }); const docs = []; - schema.post('findOne', function(doc, next) { + schema.post('findOne', function (doc, next) { docs.push(doc); next(); }); @@ -2961,16 +3235,20 @@ describe('Query', function() { assert.equal(docs.length, 0); // Shouldn't throw - const res = await Model.findOne({ name: 'Test' }).orFail(new Error('Oops')); + const res = await Model.findOne({ name: 'Test' }).orFail( + new Error('Oops') + ); assert.equal(res.name, 'Test'); assert.equal(docs.length, 1); }); - it('throws DocumentNotFoundError by default execute (gh-7409)', async function() { - - const err = await Model.findOne({ name: 'na' }). - orFail(). - then(() => null, err => err); + it('throws DocumentNotFoundError by default execute (gh-7409)', async function () { + const err = await Model.findOne({ name: 'na' }) + .orFail() + .then( + () => null, + (err) => err + ); assert.equal(err.name, 'DocumentNotFoundError', err.stack); assert.ok(err.message.indexOf('na') !== -1, err.message); assert.ok(err.message.indexOf('"Test"') !== -1, err.message); @@ -2978,28 +3256,27 @@ describe('Query', function() { }); }); - describe('getPopulatedPaths', function() { - it('doesn\'t break on a query without population (gh-6677)', async function() { + describe('getPopulatedPaths', function () { + it("doesn't break on a query without population (gh-6677)", async function () { const schema = new Schema({ name: String }); - schema.pre('findOne', function() { + schema.pre('findOne', function () { assert.deepStrictEqual(this.getPopulatedPaths(), []); }); const Model = db.model('Test', schema); - await Model.findOne({}); }); - it('returns an array of populated paths as strings (gh-6677)', async function() { + it('returns an array of populated paths as strings (gh-6677)', async function () { const otherSchema = new Schema({ name: String }); const schema = new Schema({ other: { type: Schema.Types.ObjectId, - ref: 'Test1' - } + ref: 'Test1', + }, }); - schema.pre('findOne', function() { + schema.pre('findOne', function () { assert.deepStrictEqual(this.getPopulatedPaths(), ['other']); }); @@ -3009,35 +3286,39 @@ describe('Query', function() { const other = new Other({ name: 'one' }); const test = new Test({ other: other._id }); - await other.save(); await test.save(); await Test.findOne({}).populate('other'); }); - it('returns deep populated paths (gh-7757)', function() { + it('returns deep populated paths (gh-7757)', function () { db.model('Test3', new Schema({ name: String })); db.model('Test2', new Schema({ level3: { type: String, ref: 'Test3' } })); - const L1 = db.model('Test', - new Schema({ level1: { type: String, ref: 'Test2' } })); + const L1 = db.model( + 'Test', + new Schema({ level1: { type: String, ref: 'Test2' } }) + ); const query = L1.find().populate({ path: 'level1', populate: { path: 'level2', populate: { - path: 'level3' - } - } + path: 'level3', + }, + }, }); - assert.deepEqual(query.getPopulatedPaths(), - ['level1', 'level1.level2', 'level1.level2.level3']); + assert.deepEqual(query.getPopulatedPaths(), [ + 'level1', + 'level1.level2', + 'level1.level2.level3', + ]); }); }); - describe('setUpdate', function() { - it('replaces existing update doc with new value', function() { + describe('setUpdate', function () { + it('replaces existing update doc with new value', function () { const q = new Query({}); q.set('testing', '123'); q.setUpdate({ $set: { newPath: 'newValue' } }); @@ -3046,49 +3327,53 @@ describe('Query', function() { }); }); - describe('get() (gh-7312)', function() { - it('works with using $set', function() { + describe('get() (gh-7312)', function () { + it('works with using $set', function () { const q = new Query({}); q.updateOne({}, { $set: { name: 'Jean-Luc Picard' } }); assert.equal(q.get('name'), 'Jean-Luc Picard'); }); - it('works with $set syntactic sugar', function() { + it('works with $set syntactic sugar', function () { const q = new Query({}); q.updateOne({}, { name: 'Jean-Luc Picard' }); assert.equal(q.get('name'), 'Jean-Luc Picard'); }); - it('works with mixed', function() { + it('works with mixed', function () { const q = new Query({}); q.updateOne({}, { name: 'Jean-Luc Picard', $set: { age: 59 } }); assert.equal(q.get('name'), 'Jean-Luc Picard'); }); - it('$set overwrites existing', function() { + it('$set overwrites existing', function () { const M = db.model('Test', new Schema({ name: String })); - const q = M.updateOne({}, { - name: 'Jean-Luc Picard', - $set: { name: 'William Riker' } - }, { upsert: true }); + const q = M.updateOne( + {}, + { + name: 'Jean-Luc Picard', + $set: { name: 'William Riker' }, + }, + { upsert: true } + ); assert.equal(q.get('name'), 'Jean-Luc Picard'); - return q.exec(). - then(() => M.findOne()). - then(doc => assert.equal(doc.name, 'Jean-Luc Picard')); + return q + .exec() + .then(() => M.findOne()) + .then((doc) => assert.equal(doc.name, 'Jean-Luc Picard')); }); }); - it('allows skipping timestamps in updateOne() (gh-6980)', async function() { + it('allows skipping timestamps in updateOne() (gh-6980)', async function () { const schema = new Schema({ name: String }, { timestamps: true }); const M = db.model('Test', schema); - const doc = await M.create({ name: 'foo' }); assert.ok(doc.createdAt); assert.ok(doc.updatedAt); @@ -3100,22 +3385,29 @@ describe('Query', function() { const res = await M.findOneAndUpdate({}, { name: 'bar' }, opts); assert.equal(res.name, 'bar'); - assert.ok(res.updatedAt.valueOf() <= start, - `Expected ${res.updatedAt.valueOf()} <= ${start}`); + assert.ok( + res.updatedAt.valueOf() <= start, + `Expected ${res.updatedAt.valueOf()} <= ${start}` + ); }); - it('increments timestamps for nested subdocs (gh-4412)', async function() { - const childSchema = new Schema({ name: String }, { - timestamps: true, - versionKey: false - }); - const parentSchema = new Schema({ child: childSchema }, { - // timestamps: true, - versionKey: false - }); + it('increments timestamps for nested subdocs (gh-4412)', async function () { + const childSchema = new Schema( + { name: String }, + { + timestamps: true, + versionKey: false, + } + ); + const parentSchema = new Schema( + { child: childSchema }, + { + // timestamps: true, + versionKey: false, + } + ); const Parent = db.model('Parent', parentSchema); - let doc = await Parent.create({ child: { name: 'foo' } }); assert.ok(doc.child.updatedAt); assert.ok(doc.child.createdAt); @@ -3146,22 +3438,30 @@ describe('Query', function() { assert.ok(updatedAt > start, `Expected ${updatedAt} > ${start}`); }); - describe('increments timestamps for arrays of nested subdocs (gh-4412)', function() { + describe('increments timestamps for arrays of nested subdocs (gh-4412)', function () { let Parent; - before(function() { - const childSchema = new Schema({ name: String }, { - timestamps: true, - versionKey: false - }); - const parentSchema = new Schema({ children: [childSchema] }, { - versionKey: false }); + before(function () { + const childSchema = new Schema( + { name: String }, + { + timestamps: true, + versionKey: false, + } + ); + const parentSchema = new Schema( + { children: [childSchema] }, + { + versionKey: false, + } + ); Parent = db.model('Parent', parentSchema); }); - it('$set nested property with numeric position', async function() { - - const kids = 'foo bar baz'.split(' ').map(n => { return { name: `${n}` };}); + it('$set nested property with numeric position', async function () { + const kids = 'foo bar baz'.split(' ').map((n) => { + return { name: `${n}` }; + }); const doc = await Parent.create({ children: kids }); assert.ok(doc.children[0].updatedAt && doc.children[0].createdAt); assert.ok(doc.children[1].updatedAt && doc.children[1].createdAt); @@ -3178,13 +3478,16 @@ describe('Query', function() { const updatedAt = found.children[0].updatedAt; const name = found.children[0].name; assert.ok(name, 'Luke'); - assert.ok(updatedAt.valueOf() > start.valueOf(), - `Expected ${updatedAt} > ${start}`); + assert.ok( + updatedAt.valueOf() > start.valueOf(), + `Expected ${updatedAt} > ${start}` + ); }); - it('$set numeric element', async function() { - - const kids = 'foo bar baz'.split(' ').map(n => { return { name: `${n}` };}); + it('$set numeric element', async function () { + const kids = 'foo bar baz'.split(' ').map((n) => { + return { name: `${n}` }; + }); const doc = await Parent.create({ children: kids }); assert.ok(doc.children[0].updatedAt && doc.children[0].createdAt); assert.ok(doc.children[1].updatedAt && doc.children[1].createdAt); @@ -3204,9 +3507,10 @@ describe('Query', function() { assert.ok(updatedAt > start, `Expected ${updatedAt} > ${start}`); }); - it('$set with positional operator', async function() { - - const kids = 'foo bar baz'.split(' ').map(n => { return { name: `${n}` };}); + it('$set with positional operator', async function () { + const kids = 'foo bar baz'.split(' ').map((n) => { + return { name: `${n}` }; + }); const doc = await Parent.create({ children: kids }); assert.ok(doc.children[0].updatedAt && doc.children[0].createdAt); assert.ok(doc.children[1].updatedAt && doc.children[1].createdAt); @@ -3226,13 +3530,15 @@ describe('Query', function() { assert.ok(updatedAt > start, `Expected ${updatedAt} > ${start}`); }); - it('$set with positional operator and array (gh-7106)', async function() { - + it('$set with positional operator and array (gh-7106)', async function () { const subSub = new Schema({ x: String }); const sub = new Schema({ name: String, subArr: [subSub] }); - const schema = new Schema({ arr: [sub] }, { - timestamps: true - }); + const schema = new Schema( + { arr: [sub] }, + { + timestamps: true, + } + ); const Test = db.model('Test', schema); @@ -3240,10 +3546,12 @@ describe('Query', function() { const set = { $set: { 'arr.$.subArr': [{ x: 'b' }] } }; await Test.create({ - arr: [{ - name: 'abc', - subArr: [{ x: 'a' }] - }] + arr: [ + { + name: 'abc', + subArr: [{ x: 'a' }], + }, + ], }); await Test.updateOne(cond, set); @@ -3254,16 +3562,22 @@ describe('Query', function() { }); }); - it('strictQuery option (gh-4136) (gh-7178)', async function() { - const modelSchema = new Schema({ - field: Number, - nested: { path: String } - }, { strictQuery: 'throw' }); + it('strictQuery option (gh-4136) (gh-7178)', async function () { + const modelSchema = new Schema( + { + field: Number, + nested: { path: String }, + }, + { strictQuery: 'throw' } + ); const Model = db.model('Test', modelSchema); // `find()` on a top-level path not in the schema - let err = await Model.find({ notInschema: 1 }).then(() => null, e => e); + let err = await Model.find({ notInschema: 1 }).then( + () => null, + (e) => e + ); assert.ok(err); assert.ok(err.message.indexOf('strictQuery') !== -1, err.message); @@ -3273,26 +3587,35 @@ describe('Query', function() { assert.ok(doc); // `find()` on a nested path not in the schema - err = await Model.find({ 'nested.bad': 'foo' }).then(() => null, e => e); + err = await Model.find({ 'nested.bad': 'foo' }).then( + () => null, + (e) => e + ); assert.ok(err); assert.ok(err.message.indexOf('strictQuery') !== -1, err.message); }); - it('strictQuery inherits from strict (gh-10763) (gh-4136) (gh-7178)', async function() { - const modelSchema = new Schema({ - field: Number, - nested: { path: String } - }, { strict: 'throw' }); + it('strictQuery inherits from strict (gh-10763) (gh-4136) (gh-7178)', async function () { + const modelSchema = new Schema( + { + field: Number, + nested: { path: String }, + }, + { strict: 'throw' } + ); const Model = db.model('Test', modelSchema); // `find()` on a top-level path not in the schema - const err = await Model.find({ notInschema: 1 }).then(() => null, e => e); + const err = await Model.find({ notInschema: 1 }).then( + () => null, + (e) => e + ); assert.ok(err); assert.ok(err.message.indexOf('strictQuery') !== -1, err.message); }); - it('strictQuery = true (gh-6032)', async function() { + it('strictQuery = true (gh-6032)', async function () { const modelSchema = new Schema({ field: Number }, { strictQuery: true }); const Model = db.model('Test', modelSchema); @@ -3304,13 +3627,12 @@ describe('Query', function() { assert.equal(docs.length, 1); }); - it('function defaults run after query result is inited (gh-7182)', async function() { + it('function defaults run after query result is inited (gh-7182)', async function () { const schema = new Schema({ kind: String, hasDefault: String }); - schema.path('hasDefault').default(function() { + schema.path('hasDefault').default(function () { return this.kind === 'test' ? 'success' : 'fail'; }); - const Model = db.model('Test', schema); await Model.create({ kind: 'test' }); @@ -3320,72 +3642,79 @@ describe('Query', function() { assert.equal(doc.hasDefault, 'success'); }); - it('merging objectids with where() (gh-7360)', function() { + it('merging objectids with where() (gh-7360)', function () { const Test = db.model('Test', new Schema({})); - return Test.create({}). - then(doc => Test.find({ _id: doc._id.toString() }).where({ _id: doc._id })). - then(res => assert.equal(res.length, 1)); + return Test.create({}) + .then((doc) => + Test.find({ _id: doc._id.toString() }).where({ _id: doc._id }) + ) + .then((res) => assert.equal(res.length, 1)); }); - it('maxTimeMS() (gh-7254)', async function() { + it('maxTimeMS() (gh-7254)', async function () { const Model = db.model('Test', new Schema({})); - await Model.create({}); - const res = await Model.find({ $where: 'sleep(1000) || true' }). - maxTimeMS(10). - then(() => null, err => err); + const res = await Model.find({ $where: 'sleep(1000) || true' }) + .maxTimeMS(10) + .then( + () => null, + (err) => err + ); assert.ok(res); assert.ok(res.message.indexOf('time limit') !== -1, res.message); }); - it('connection-level maxTimeMS() (gh-4066)', async function() { + it('connection-level maxTimeMS() (gh-4066)', async function () { db.options = db.options || {}; db.options.maxTimeMS = 10; const Model = db.model('Test', new Schema({})); - await Model.create({}); - const res = await Model.find({ $where: 'sleep(250) || true' }). - then(() => null, err => err); + const res = await Model.find({ $where: 'sleep(250) || true' }).then( + () => null, + (err) => err + ); assert.ok(res); assert.ok(res.message.indexOf('time limit') !== -1, res.message); delete db.options.maxTimeMS; }); - it('mongoose-level maxTimeMS() (gh-4066)', async function() { + it('mongoose-level maxTimeMS() (gh-4066)', async function () { db.base.options = db.base.options || {}; db.base.options.maxTimeMS = 10; const Model = db.model('Test', new Schema({})); - await Model.create({}); - const res = await Model.find({ $where: 'sleep(250) || true' }). - then(() => null, err => err); + const res = await Model.find({ $where: 'sleep(250) || true' }).then( + () => null, + (err) => err + ); assert.ok(res); assert.ok(res.message.indexOf('time limit') !== -1, res.message); delete db.base.options.maxTimeMS; }); - it('throws error with updateOne() and overwrite (gh-7475)', function() { + it('throws error with updateOne() and overwrite (gh-7475)', function () { const Model = db.model('Test', Schema({ name: String })); return Model.updateOne({}, { name: 'bar' }, { overwrite: true }).then( - () => { throw new Error('Should have failed'); }, - err => assert.ok(err.message.indexOf('updateOne') !== -1) + () => { + throw new Error('Should have failed'); + }, + (err) => assert.ok(err.message.indexOf('updateOne') !== -1) ); }); - it('sets deletedCount on result of remove() (gh-7629)', async function() { + it('sets deletedCount on result of remove() (gh-7629)', async function () { const schema = new Schema({ name: String }); const Model = db.model('Test', schema); - await Model.create({ name: 'foo' }); let res = await Model.remove({}); @@ -3395,22 +3724,21 @@ describe('Query', function() { assert.strictEqual(res.deletedCount, 0); }); - describe('merge()', function() { - it('copies populate() (gh-1790)', async function() { + describe('merge()', function () { + it('copies populate() (gh-1790)', async function () { const Car = db.model('Car', { color: String, model: String, owner: { type: Schema.Types.ObjectId, - ref: 'Person' - } + ref: 'Person', + }, }); const Person = db.model('Person', { - name: String + name: String, }); - const val = await Person.create({ name: 'Val' }); await Car.create({ color: 'Brown', model: 'Subaru', owner: val._id }); @@ -3422,22 +3750,22 @@ describe('Query', function() { }); }); - describe('Query#validate() (gh-7984)', function() { - it('middleware', function() { + describe('Query#validate() (gh-7984)', function () { + it('middleware', function () { const schema = new Schema({ password: { type: String, - validate: v => v.length >= 6, - required: true - } + validate: (v) => v.length >= 6, + required: true, + }, }); let docCalls = 0; - schema.post('validate', function() { + schema.post('validate', function () { ++docCalls; }); let queryCalls = 0; - schema.post('validate', { query: true }, function() { + schema.post('validate', { query: true }, function () { ++queryCalls; const pw = this.get('password'); assert.equal(pw, '6chars'); @@ -3447,34 +3775,37 @@ describe('Query', function() { const M = db.model('Test', schema); const opts = { runValidators: true, upsert: true, new: true }; - return M.findOneAndUpdate({}, { password: '6chars' }, opts).then(doc => { - assert.equal(docCalls, 0); - assert.equal(queryCalls, 1); - assert.equal(doc.password, 'encryptedpassword'); - }); + return M.findOneAndUpdate({}, { password: '6chars' }, opts).then( + (doc) => { + assert.equal(docCalls, 0); + assert.equal(queryCalls, 1); + assert.equal(doc.password, 'encryptedpassword'); + } + ); }); - it('pre("validate") errors (gh-7187)', async function() { + it('pre("validate") errors (gh-7187)', async function () { const addressSchema = Schema({ countryId: String }); - addressSchema.pre('validate', { query: true }, function() { + addressSchema.pre('validate', { query: true }, function () { throw new Error('Oops!'); }); const contactSchema = Schema({ addresses: [addressSchema] }); const Contact = db.model('Test', contactSchema); const update = { addresses: [{ countryId: 'foo' }] }; - const err = await Contact.updateOne( - {}, - update, - { runValidators: true } - ).then(() => null, err => err); + const err = await Contact.updateOne({}, update, { + runValidators: true, + }).then( + () => null, + (err) => err + ); assert.ok(err.errors['addresses.0']); assert.equal(err.errors['addresses.0'].message, 'Oops!'); }); }); - it('query with top-level _bsontype (gh-8222) (gh-8268)', async function() { + it('query with top-level _bsontype (gh-8222) (gh-8268)', async function () { const userSchema = Schema({ token: String }, { strictQuery: true }); const User = db.model('Test', userSchema); @@ -3488,67 +3819,80 @@ describe('Query', function() { assert.equal(doc.token, 'rightToken'); }); - it('casts $elemMatch with dbrefs (gh-8577)', async function() { + it('casts $elemMatch with dbrefs (gh-8577)', async function () { const ChatSchema = new Schema({ - members: [{ - $ref: String, - $id: mongoose.ObjectId, - $db: String - }] + members: [ + { + $ref: String, + $id: mongoose.ObjectId, + $db: String, + }, + ], }); const Chat = db.model('Test', ChatSchema); - const doc = await Chat.create({ - members: [{ $ref: 'foo', $id: new mongoose.Types.ObjectId(), $db: 'foo' }] + members: [ + { $ref: 'foo', $id: new mongoose.Types.ObjectId(), $db: 'foo' }, + ], }); const res = await Chat.findOne({ - members: { $elemMatch: { $id: doc.members[0].$id } } + members: { $elemMatch: { $id: doc.members[0].$id } }, }); assert.ok(res); }); - it('throws an error if executed multiple times (gh-7398)', async function() { + it('throws an error if executed multiple times (gh-7398)', async function () { const Test = db.model('Test', Schema({ name: String })); - const q = Test.findOne(); await q; - let err = await q.then(() => null, err => err); + let err = await q.then( + () => null, + (err) => err + ); assert.ok(err); assert.equal(err.name, 'MongooseError'); assert.equal(err.message, 'Query was already executed: Test.findOne({})'); assert.ok(err.originalStack); const cb = () => {}; - err = await Test.find(cb).then(() => null, err => err); + err = await Test.find(cb).then( + () => null, + (err) => err + ); assert.ok(err); assert.equal(err.name, 'MongooseError'); assert.equal(err.message, 'Query was already executed: Test.find({})'); assert.ok(err.originalStack); - err = await q.clone().then(() => null, err => err); + err = await q.clone().then( + () => null, + (err) => err + ); assert.ifError(err); }); - describe('stack traces', function() { - it('includes calling file for filter cast errors (gh-8691)', async function() { + describe('stack traces', function () { + it('includes calling file for filter cast errors (gh-8691)', async function () { const toCheck = ['find', 'findOne', 'deleteOne']; const Model = db.model('Test', Schema({})); - for (const fn of toCheck) { - const err = await Model[fn]({ _id: 'fail' }).then(() => null, err => err); + const err = await Model[fn]({ _id: 'fail' }).then( + () => null, + (err) => err + ); assert.ok(err); assert.ok(err.stack.includes(__filename), err.stack); } }); }); - it('setter priorVal (gh-8629)', function() { + it('setter priorVal (gh-8629)', function () { const priorVals = []; const schema = Schema({ name: { @@ -3556,29 +3900,30 @@ describe('Query', function() { set: (v, priorVal) => { priorVals.push(priorVal); return v; - } - } + }, + }, }); const Model = db.model('Test', schema); - return Model.updateOne({}, { name: 'bar' }).exec(). - then(() => assert.deepEqual(priorVals, [null])); + return Model.updateOne({}, { name: 'bar' }) + .exec() + .then(() => assert.deepEqual(priorVals, [null])); }); - describe('clone', function() { + describe('clone', function () { let Model; - beforeEach(function() { + beforeEach(function () { const schema = new Schema({ name: String, age: Number }); Model = db.model('Test', schema); return Model.create([ { name: 'Jean-Luc Picard', age: 59 }, - { name: 'Will Riker', age: 29 } + { name: 'Will Riker', age: 29 }, ]); }); - it('with findOne', async function() { + it('with findOne', async function () { const q = Model.findOne({ age: 29 }); const q2 = q.clone(); @@ -3595,7 +3940,7 @@ describe('Query', function() { assert.equal(doc.name, 'Will Riker'); }); - it('with deleteOne', async function() { + it('with deleteOne', async function () { const q = Model.deleteOne({ age: 29 }); await q; @@ -3608,8 +3953,11 @@ describe('Query', function() { assert.equal(await Model.findOne({ name: 'Will Riker' }), null); }); - it('with updateOne', async function() { - const q = Model.updateOne({ name: 'Will Riker' }, { name: 'Thomas Riker' }); + it('with updateOne', async function () { + const q = Model.updateOne( + { name: 'Will Riker' }, + { name: 'Thomas Riker' } + ); await q; assert.equal(await Model.findOne({ name: 'Will Riker' }), null); @@ -3622,7 +3970,7 @@ describe('Query', function() { assert.equal(await Model.findOne({ name: 'Will Riker' }), null); }); - it('with distinct', async function() { + it('with distinct', async function () { const q = Model.distinct('name'); const res = await q; @@ -3634,7 +3982,7 @@ describe('Query', function() { assert.deepEqual(res.sort(), ['Jean-Luc Picard', 'Will Riker']); }); - it('with hooks (gh-12365)', async function() { + it('with hooks (gh-12365)', async function () { db.deleteModel('Test'); const schema = new Schema({ name: String, age: Number }); @@ -3647,16 +3995,24 @@ describe('Query', function() { const res = await Model.find().clone(); assert.strictEqual(called, 1); assert.equal(res.length, 2); - assert.deepEqual(res.map(doc => doc.name).sort(), ['Jean-Luc Picard', 'Will Riker']); + assert.deepEqual(res.map((doc) => doc.name).sort(), [ + 'Jean-Luc Picard', + 'Will Riker', + ]); }); }); - it('casts filter according to discriminator schema if in filter (gh-8881)', async function() { - const userSchema = new Schema({ name: String }, { discriminatorKey: 'kind' }); + it('casts filter according to discriminator schema if in filter (gh-8881)', async function () { + const userSchema = new Schema( + { name: String }, + { discriminatorKey: 'kind' } + ); const User = db.model('User', userSchema); - - const UserWithAge = User.discriminator('UserWithAge', new Schema({ age: Number })); + const UserWithAge = User.discriminator( + 'UserWithAge', + new Schema({ age: Number }) + ); await UserWithAge.create({ name: 'Hafez', age: 25 }); // should cast `age` to number @@ -3666,26 +4022,31 @@ describe('Query', function() { assert.equal(user.age, 25); }); - it('casts update object according to child discriminator schema when `discriminatorKey` is present (gh-8982)', async function() { + it('casts update object according to child discriminator schema when `discriminatorKey` is present (gh-8982)', async function () { const userSchema = new Schema({}, { discriminatorKey: 'kind' }); const Person = db.model('Person', userSchema); - - const Worker = Person.discriminator('Worker', new Schema({ locations: [String] })); + const Worker = Person.discriminator( + 'Worker', + new Schema({ locations: [String] }) + ); const worker = await Worker.create({ locations: ['US'] }); // should cast `update` according to `Worker` schema - await Person.updateOne({ _id: worker._id, kind: 'Worker' }, { $push: { locations: 'UK' } }); + await Person.updateOne( + { _id: worker._id, kind: 'Worker' }, + { $push: { locations: 'UK' } } + ); const person = await Person.findOne({ _id: worker._id }); assert.deepEqual(person.locations, ['US', 'UK']); }); - it('allows disabling `setDefaultsOnInsert` (gh-8410)', function() { + it('allows disabling `setDefaultsOnInsert` (gh-8410)', function () { const schema = new Schema({ title: String, - genre: { type: String, default: 'Action' } + genre: { type: String, default: 'Action' }, }); const Movie = db.model('Movie', schema); @@ -3696,42 +4057,40 @@ describe('Query', function() { new: true, upsert: true, setDefaultsOnInsert: false, - lean: true + lean: true, }; - return Movie.deleteMany({}). - then(() => Movie.findOneAndUpdate(query, update, options)). - then(doc => { + return Movie.deleteMany({}) + .then(() => Movie.findOneAndUpdate(query, update, options)) + .then((doc) => { assert.strictEqual(doc.genre, void 0); }); }); - it('throws readable error if `$and` and `$or` contain non-objects (gh-8948)', async function() { + it('throws readable error if `$and` and `$or` contain non-objects (gh-8948)', async function () { const userSchema = new Schema({ name: String }); const Person = db.model('Person', userSchema); - - let err = await Person.find({ $and: [null] }).catch(err => err); + let err = await Person.find({ $and: [null] }).catch((err) => err); assert.equal(err.name, 'CastError'); assert.equal(err.path, '$and.0'); - err = await Person.find({ $or: [false] }).catch(err => err); + err = await Person.find({ $or: [false] }).catch((err) => err); assert.equal(err.name, 'CastError'); assert.equal(err.path, '$or.0'); - err = await Person.find({ $nor: ['not an object'] }).catch(err => err); + err = await Person.find({ $nor: ['not an object'] }).catch((err) => err); assert.equal(err.name, 'CastError'); assert.equal(err.path, '$nor.0'); }); - it('includes `undefined` in filters (gh-3944)', async function() { + it('includes `undefined` in filters (gh-3944)', async function () { const userSchema = new Schema({ name: String, pwd: String }); const Person = db.model('Person', userSchema); - await Person.create([ { name: 'test1', pwd: 'my secret' }, - { name: 'test2', pwd: null } + { name: 'test2', pwd: null }, ]); let res = await Person.findOne({ name: 'test1', pwd: void 0 }); @@ -3741,28 +4100,36 @@ describe('Query', function() { assert.equal(res.name, 'test2'); }); - it('handles push with array filters (gh-9977)', async function() { - const questionSchema = new Schema({ - question_type: { type: String, enum: ['mcq', 'essay'] } - }, { discriminatorKey: 'question_type', strict: 'throw' }); + it('handles push with array filters (gh-9977)', async function () { + const questionSchema = new Schema( + { + question_type: { type: String, enum: ['mcq', 'essay'] }, + }, + { discriminatorKey: 'question_type', strict: 'throw' } + ); - const quizSchema = new Schema({ - quiz_title: String, - questions: [questionSchema] - }, { strict: 'throw' }); + const quizSchema = new Schema( + { + quiz_title: String, + questions: [questionSchema], + }, + { strict: 'throw' } + ); const Quiz = db.model('Test', quizSchema); - const mcqQuestionSchema = new Schema({ - text: String, - choices: [{ choice_text: String, is_correct: Boolean }] - }, { strict: 'throw' }); + const mcqQuestionSchema = new Schema( + { + text: String, + choices: [{ choice_text: String, is_correct: Boolean }], + }, + { strict: 'throw' } + ); quizSchema.path('questions').discriminator('mcq', mcqQuestionSchema); const id1 = new mongoose.Types.ObjectId(); const id2 = new mongoose.Types.ObjectId(); - let quiz = await Quiz.create({ quiz_title: 'quiz', questions: [ @@ -3772,45 +4139,51 @@ describe('Query', function() { text: 'A or B?', choices: [ { choice_text: 'A', is_correct: false }, - { choice_text: 'B', is_correct: true } - ] + { choice_text: 'B', is_correct: true }, + ], }, { _id: id2, - question_type: 'mcq' - } - ] + question_type: 'mcq', + }, + ], }); - const filter = { questions: { $elemMatch: { _id: id2, question_type: 'mcq' } } }; + const filter = { + questions: { $elemMatch: { _id: id2, question_type: 'mcq' } }, + }; await Quiz.updateOne(filter, { $push: { 'questions.$.choices': { choice_text: 'choice 1', - is_correct: false - } - } + is_correct: false, + }, + }, }); quiz = await Quiz.findById(quiz); assert.equal(quiz.questions[1].choices.length, 1); assert.equal(quiz.questions[1].choices[0].choice_text, 'choice 1'); - await Quiz.updateOne({ questions: { $elemMatch: { _id: id2 } } }, { - $push: { - 'questions.$[q].choices': { - choice_text: 'choice 3', - is_correct: false - } - } - }, { arrayFilters: [{ 'q.question_type': 'mcq' }] }); + await Quiz.updateOne( + { questions: { $elemMatch: { _id: id2 } } }, + { + $push: { + 'questions.$[q].choices': { + choice_text: 'choice 3', + is_correct: false, + }, + }, + }, + { arrayFilters: [{ 'q.question_type': 'mcq' }] } + ); quiz = await Quiz.findById(quiz); assert.equal(quiz.questions[1].choices.length, 2); assert.equal(quiz.questions[1].choices[1].choice_text, 'choice 3'); }); - it('Query#pre() (gh-9784)', async function() { + it('Query#pre() (gh-9784)', async function () { const Question = db.model('Test', Schema({ answer: Number })); const q1 = Question.find({ answer: 42 }); @@ -3826,16 +4199,18 @@ describe('Query', function() { assert.equal(called.length, 1); }); - it('applies schema-level `select` on arrays (gh-10029)', function() { + it('applies schema-level `select` on arrays (gh-10029)', function () { const testSchema = new mongoose.Schema({ doesntpopulate: { type: [mongoose.Schema.Types.ObjectId], - select: false + select: false, }, - populatescorrectly: [{ - type: mongoose.Schema.Types.ObjectId, - select: false - }] + populatescorrectly: [ + { + type: mongoose.Schema.Types.ObjectId, + select: false, + }, + ], }); const Test = db.model('Test', testSchema); @@ -3845,9 +4220,9 @@ describe('Query', function() { assert.deepEqual(q._fields, { doesntpopulate: 0, populatescorrectly: 0 }); }); - it('sets `writeConcern` option correctly (gh-10009)', function() { + it('sets `writeConcern` option correctly (gh-10009)', function () { const testSchema = new mongoose.Schema({ - name: String + name: String, }); const Test = db.model('Test', testSchema); @@ -3856,82 +4231,103 @@ describe('Query', function() { assert.deepEqual(q.options.writeConcern, { w: 'majority', wtimeout: 1000 }); }); - it('no longer has the deprecation warning message with writeConcern gh-10083', async function() { + it('no longer has the deprecation warning message with writeConcern gh-10083', async function () { const MySchema = new mongoose.Schema( { _id: { type: Number, required: true }, op: { type: String, required: true }, size: { type: Number, required: true }, - totalSize: { type: Number, required: true } + totalSize: { type: Number, required: true }, }, { versionKey: false, writeConcern: { w: 'majority', j: true, - wtimeout: 15000 - } + wtimeout: 15000, + }, } ); const Test = db.model('Test', MySchema); // pops up on creation of model - const entry = await Test.create({ _id: 12345678, op: 'help', size: 54, totalSize: 104 }); + const entry = await Test.create({ + _id: 12345678, + op: 'help', + size: 54, + totalSize: 104, + }); await entry.save(); }); - it('sanitizeProjection option (gh-10243)', function() { + it('sanitizeProjection option (gh-10243)', function () { const MySchema = Schema({ name: String, email: String }); const Test = db.model('Test', MySchema); let q = Test.find().select({ email: '$name' }); assert.deepEqual(q._fields, { email: '$name' }); - q = Test.find().setOptions({ sanitizeProjection: true }).select({ email: '$name' }); + q = Test.find() + .setOptions({ sanitizeProjection: true }) + .select({ email: '$name' }); assert.deepEqual(q._fields, { email: 1 }); - q = Test.find().select({ email: '$name' }).setOptions({ sanitizeProjection: true }); + q = Test.find() + .select({ email: '$name' }) + .setOptions({ sanitizeProjection: true }); assert.deepEqual(q._fields, { email: 1 }); }); - it('sanitizeFilter option (gh-3944)', function() { + it('sanitizeFilter option (gh-3944)', function () { const MySchema = Schema({ username: String, pwd: String }); const Test = db.model('Test', MySchema); - let q = Test.find({ username: 'val', pwd: 'my secret' }).setOptions({ sanitizeFilter: true }); + let q = Test.find({ username: 'val', pwd: 'my secret' }).setOptions({ + sanitizeFilter: true, + }); q._castConditions(); assert.ifError(q.error()); assert.deepEqual(q._conditions, { username: 'val', pwd: 'my secret' }); - q = Test.find({ username: 'val', pwd: { $ne: null } }).setOptions({ sanitizeFilter: true }); + q = Test.find({ username: 'val', pwd: { $ne: null } }).setOptions({ + sanitizeFilter: true, + }); q._castConditions(); assert.ok(q.error()); assert.equal(q.error().name, 'CastError'); - q = Test.find({ username: 'val', pwd: mongoose.trusted({ $gt: null }) }). - setOptions({ sanitizeFilter: true }); + q = Test.find({ + username: 'val', + pwd: mongoose.trusted({ $gt: null }), + }).setOptions({ sanitizeFilter: true }); q._castConditions(); assert.ifError(q.error()); assert.deepEqual(q._conditions, { username: 'val', pwd: { $gt: null } }); }); - it('should not error when $not is used with $size (gh-10716)', async function() { + it('should not error when $not is used with $size (gh-10716)', async function () { const barSchema = Schema({ - bar: String + bar: String, }); const testSchema = Schema({ foo: String, bars: [barSchema] }); const Test = db.model('Zulu', testSchema); - const entry = await Test.create({ foo: 'hello', bars: [{ bar: 'world' }, { bar: 'world1' }] }); + const entry = await Test.create({ + foo: 'hello', + bars: [{ bar: 'world' }, { bar: 'world1' }], + }); await entry.save(); const foos = await Test.find({ bars: { $not: { $size: 0 } } }); assert.ok(foos); }); - it('should not error when $not is used on an array of strings (gh-11467)', async function() { + it('should not error when $not is used on an array of strings (gh-11467)', async function () { const testSchema = Schema({ names: [String] }); const Test = db.model('Test', testSchema); await Test.create([{ names: ['foo'] }, { names: ['bar'] }]); let res = await Test.find({ names: { $not: /foo/ } }); - assert.deepStrictEqual(res.map(el => el.names), [['bar']]); + assert.deepStrictEqual( + res.map((el) => el.names), + [['bar']] + ); // MongoDB server < 4.4 doesn't support `{ $not: { $regex } }`, see: // https://github.com/Automattic/mongoose/runs/5441062834?check_suite_focus=true @@ -3941,24 +4337,28 @@ describe('Query', function() { } res = await Test.find({ names: { $not: { $regex: 'foo' } } }); - assert.deepStrictEqual(res.map(el => el.names), [['bar']]); + assert.deepStrictEqual( + res.map((el) => el.names), + [['bar']] + ); }); - it('adding `exec` option does not affect the query (gh-11416)', async() => { + it('adding `exec` option does not affect the query (gh-11416)', async () => { const userSchema = new Schema({ - name: { type: String } + name: { type: String }, }); - const User = db.model('User', userSchema); const createdUser = await User.create({ name: 'Hafez' }); - const users = await User.find({ _id: createdUser._id }).setOptions({ exec: false }); + const users = await User.find({ _id: createdUser._id }).setOptions({ + exec: false, + }); assert.ok(users.length, 1); }); - it('handles queries with EJSON deserialized RegExps (gh-11597)', async function() { + it('handles queries with EJSON deserialized RegExps (gh-11597)', async function () { const testSchema = new mongoose.Schema({ - name: String + name: String, }); const Test = db.model('Test', testSchema); @@ -3972,55 +4372,67 @@ describe('Query', function() { assert.equal(result[0].name, '@foo.com'); }); - it('should return query helper supplied in schema options query property instead of undefined', function(done) { - const Model = db.model('Test', new Schema({ - userName: { - type: String, - required: [true, 'userName is required'] - } - }, { - query: { - byUserName(userName) { - return this.where({ userName }); + it('should return query helper supplied in schema options query property instead of undefined', function (done) { + const Model = db.model( + 'Test', + new Schema( + { + userName: { + type: String, + required: [true, 'userName is required'], + }, + }, + { + query: { + byUserName(userName) { + return this.where({ userName }); + }, + }, } - } - })); + ) + ); - Model.create({ userName: 'test' }, function(error) { + Model.create({ userName: 'test' }, function (error) { if (error instanceof Error) { return done(error); } - Model.find().byUserName('test').exec(function(error, docs) { - if (error instanceof Error) { - return done(error); - } - assert.equal(docs.length, 1); - assert.equal(docs[0].userName, 'test'); - done(); - }); + Model.find() + .byUserName('test') + .exec(function (error, docs) { + if (error instanceof Error) { + return done(error); + } + assert.equal(docs.length, 1); + assert.equal(docs[0].userName, 'test'); + done(); + }); }); }); - it('allows a transform option for lean on a query (gh-10423)', async function() { + it('allows a transform option for lean on a query (gh-10423)', async function () { const arraySchema = new mongoose.Schema({ - sub: String + sub: String, }); const subDoc = new mongoose.Schema({ - nickName: String + nickName: String, }); const testSchema = new mongoose.Schema({ name: String, foo: [arraySchema], - otherName: subDoc + otherName: subDoc, }); const Test = db.model('Test', testSchema); - await Test.create({ name: 'foo', foo: [{ sub: 'Test' }, { sub: 'Testerson' }], otherName: { nickName: 'Bar' } }); + await Test.create({ + name: 'foo', + foo: [{ sub: 'Test' }, { sub: 'Testerson' }], + otherName: { nickName: 'Bar' }, + }); const result = await Test.find().lean({ transform: (doc) => { delete doc._id; return doc; - } + }, }); assert.strictEqual(result[0]._id, undefined); assert.strictEqual(result[0].otherName._id, undefined); @@ -4031,7 +4443,7 @@ describe('Query', function() { transform: (doc) => { delete doc._id; return doc; - } + }, }); assert.strictEqual(single._id, undefined); assert.strictEqual(single.otherName._id, undefined); @@ -4039,17 +4451,17 @@ describe('Query', function() { assert.strictEqual(single.foo[0]._id, undefined); }); - it('handles a lean transform that deletes _id with populate (gh-12143) (gh-10423)', async function() { + it('handles a lean transform that deletes _id with populate (gh-12143) (gh-10423)', async function () { const testSchema = Schema({ name: String, user: { type: mongoose.Types.ObjectId, - ref: 'User' - } + ref: 'User', + }, }); const userSchema = Schema({ - name: String + name: String, }); const Test = db.model('Test', testSchema); @@ -4058,49 +4470,50 @@ describe('Query', function() { const user = await User.create({ name: 'John Smith' }); let test = await Test.create({ name: 'test', user }); - test = await Test.findById(test).populate('user').lean({ - transform: (doc) => { - delete doc._id; - delete doc.__v; - return doc; - } - }); + test = await Test.findById(test) + .populate('user') + .lean({ + transform: (doc) => { + delete doc._id; + delete doc.__v; + return doc; + }, + }); assert.ok(test); assert.deepStrictEqual(test, { name: 'test', - user: { name: 'John Smith' } + user: { name: 'John Smith' }, }); }); - it('skips applying default projections over slice projections (gh-11940)', async function() { + it('skips applying default projections over slice projections (gh-11940)', async function () { const commentSchema = new mongoose.Schema({ - comment: String + comment: String, }); const testSchema = new mongoose.Schema({ name: String, - comments: { type: [commentSchema], select: false } + comments: { type: [commentSchema], select: false }, }); const Test = db.model('Test', testSchema); const { _id } = await Test.create({ name: 'Test', - comments: [{ comment: 'test1' }, { comment: 'test2' }] + comments: [{ comment: 'test1' }, { comment: 'test2' }], }); const doc = await Test.findById(_id).slice('comments', [1, 1]); assert.equal(doc.comments.length, 1); assert.equal(doc.comments[0].comment, 'test2'); - }); - describe('set()', function() { - it('overwrites top-level keys if setting to undefined (gh-12155)', function() { + describe('set()', function () { + it('overwrites top-level keys if setting to undefined (gh-12155)', function () { const testSchema = new mongoose.Schema({ key: String, - prop: String + prop: String, }); const Test = db.model('Test', testSchema); @@ -4111,28 +4524,28 @@ describe('Query', function() { assert.deepEqual(update, { $set: { key: undefined }, - prop: 'foo' + prop: 'foo', }); }); }); - it('select: false is ignored for type Map (gh-12445)', async function() { + it('select: false is ignored for type Map (gh-12445)', async function () { const testSchema = new mongoose.Schema({ select: { type: Map, - of: Object + of: Object, }, doNotSelect: { type: Map, of: Object, - select: false - } + select: false, + }, }); const Test = db.model('Test', testSchema); await Test.create({ select: { key: { some: 'value' } }, - doNotSelect: { otherKey: { someOther: 'value' } } + doNotSelect: { otherKey: { someOther: 'value' } }, }); const item = await Test.findOne(); @@ -4140,14 +4553,14 @@ describe('Query', function() { assert.equal(item.doNotSelect, undefined); }); - it('Map field with select: false is selected when explicitly requested (gh-12603)', async function() { + it('Map field with select: false is selected when explicitly requested (gh-12603)', async function () { const testSchema = new mongoose.Schema({ title: String, body: { type: Map, of: { en: String, pt: String }, - select: false - } + select: false, + }, }); const Test = db.model('Test', testSchema); @@ -4155,8 +4568,8 @@ describe('Query', function() { title: 'test', body: { A: { en: 'en test A value', pt: 'pt test A value' }, - B: { en: 'en test B value', pt: 'pt test B value' } - } + B: { en: 'en test B value', pt: 'pt test B value' }, + }, }); const item = await Test.findOne({}).select('+body'); @@ -4168,7 +4581,7 @@ describe('Query', function() { assert.equal(item2.get('body.A.en'), 'en test A value'); }); - it('treats ObjectId as object with `_id` for `merge()` (gh-12325)', async function() { + it('treats ObjectId as object with `_id` for `merge()` (gh-12325)', async function () { const testSchema = new mongoose.Schema({ name: String }); const Test = db.model('Test', testSchema); const _id = new mongoose.Types.ObjectId(); @@ -4184,9 +4597,12 @@ describe('Query', function() { assert.equal(q.getFilter()._id.toHexString(), _id.toHexString()); }); - it('avoid throwing error when modifying nested field with same name as discriminator key (gh-12517)', async function() { + it('avoid throwing error when modifying nested field with same name as discriminator key (gh-12517)', async function () { const options = { discriminatorKey: 'kind', strict: 'throw' }; - const testSchema = new mongoose.Schema({ name: String, kind: String, animals: { kind: String, world: String } }, options); + const testSchema = new mongoose.Schema( + { name: String, kind: String, animals: { kind: String, world: String } }, + options + ); const Test = db.model('Test', testSchema); Test.discriminator( @@ -4196,7 +4612,7 @@ describe('Query', function() { const newItem = await Test.create({ name: 'Name', - animals: { kind: 'Kind', world: 'World' } + animals: { kind: 'Kind', world: 'World' }, }); const updatedItem = await Test.findByIdAndUpdate( @@ -4204,32 +4620,38 @@ describe('Query', function() { { $set: { name: 'Name2', - animals: { kind: 'Kind2', world: 'World2' } - } + animals: { kind: 'Kind2', world: 'World2' }, + }, }, { - new: true + new: true, } ); assert.deepEqual(updatedItem.animals, { kind: 'Kind2', world: 'World2' }); - await assert.rejects(async() => { - await Test.findByIdAndUpdate( - newItem._id, - { + await assert.rejects( + async () => { + await Test.findByIdAndUpdate(newItem._id, { $set: { name: 'Name2', - kind: 'Kind2' - } - } - ); - }, { message: 'Can\'t modify discriminator key "kind" on discriminator model' }); + kind: 'Kind2', + }, + }); + }, + { + message: + 'Can\'t modify discriminator key "kind" on discriminator model', + } + ); }); - it('avoid throwing error when modifying field with same name as nested discriminator key (gh-12517)', async function() { + it('avoid throwing error when modifying field with same name as nested discriminator key (gh-12517)', async function () { const options = { discriminatorKey: 'animals.kind', strict: 'throw' }; - const testSchema = new mongoose.Schema({ name: String, kind: String, animals: { kind: String, world: String } }, options); + const testSchema = new mongoose.Schema( + { name: String, kind: String, animals: { kind: String, world: String } }, + options + ); const Test = db.model('Test', testSchema); Test.discriminator( @@ -4240,7 +4662,7 @@ describe('Query', function() { const newItem = await Test.create({ name: 'Name', kind: 'Kind', - animals: { world: 'World' } + animals: { world: 'World' }, }); const updatedItem = await Test.findByIdAndUpdate( @@ -4248,30 +4670,33 @@ describe('Query', function() { { $set: { name: 'Name2', - kind: 'Kind2' - } + kind: 'Kind2', + }, }, { - new: true + new: true, } ); assert.equal(updatedItem.name, 'Name2'); assert.equal(updatedItem.kind, 'Kind2'); - await assert.rejects(async() => { - await Test.findByIdAndUpdate( - newItem._id, - { + await assert.rejects( + async () => { + await Test.findByIdAndUpdate(newItem._id, { $set: { - animals: { kind: 'Kind2', world: 'World2' } - } - } - ); - }, { message: 'Can\'t modify discriminator key "animals.kind" on discriminator model' }); + animals: { kind: 'Kind2', world: 'World2' }, + }, + }); + }, + { + message: + 'Can\'t modify discriminator key "animals.kind" on discriminator model', + } + ); }); - it('global strictQuery should work if applied after schema creation (gh-12703)', async() => { + it('global strictQuery should work if applied after schema creation (gh-12703)', async () => { const m = new mongoose.Mongoose(); await m.connect(start.uri); @@ -4283,13 +4708,13 @@ describe('Query', function() { m.set('strictQuery', false); await Test.create({ - title: 'chimichanga' + title: 'chimichanga', }); await Test.create({ - title: 'burrito bowl' + title: 'burrito bowl', }); await Test.create({ - title: 'taco supreme' + title: 'taco supreme', }); const cond = { @@ -4297,20 +4722,46 @@ describe('Query', function() { { title: { $regex: 'urri', - $options: 'i' - } + $options: 'i', + }, }, { name: { $regex: 'urri', - $options: 'i' - } - } - ] + $options: 'i', + }, + }, + ], }; const found = await Test.find(cond); assert.strictEqual(found.length, 1); assert.strictEqual(found[0].title, 'burrito bowl'); }); + + it('update operation should remove fields set to undefined (gh-12794)', async () => { + const m = new mongoose.Mongoose(); + + await m.connect(start.uri); + + const schema = new mongoose.Schema({ title: String }); + + const Test = m.model('test', schema); + + const doc = await Test.create({ + title: 'test', + }); + + assert.strictEqual(doc.title, 'test'); + + const updatedDoc = await Test.findOneAndUpdate( + { + _id: doc._id, + }, + { title: undefined }, + { returnOriginal: false } + ); + + assert.ok(updatedDoc.title === undefined); + }); }); From 34a331aed5ee1c139e981b879c1de0a7069528b7 Mon Sep 17 00:00:00 2001 From: Luca Pizzini Date: Wed, 14 Dec 2022 10:01:39 +0100 Subject: [PATCH 14/23] fix lint --- test/query.test.js | 2743 +++++++++++++++++++------------------------- 1 file changed, 1159 insertions(+), 1584 deletions(-) diff --git a/test/query.test.js b/test/query.test.js index c03689eeef8..3898bfc1422 100644 --- a/test/query.test.js +++ b/test/query.test.js @@ -19,14 +19,14 @@ const DocumentObjectId = mongoose.Types.ObjectId; * Test. */ -describe('Query', function () { +describe('Query', function() { let commentSchema; let productSchema; let db; - before(function () { + before(function() { commentSchema = new Schema({ - text: String, + text: String }); productSchema = new Schema({ @@ -35,15 +35,15 @@ describe('Query', function () { ids: [Schema.ObjectId], strings: [String], numbers: [Number], - comments: [commentSchema], + comments: [commentSchema] }); }); - before(function () { + before(function() { db = start(); }); - after(async function () { + after(async function() { await db.close(); }); @@ -51,8 +51,8 @@ describe('Query', function () { afterEach(() => util.clearTestData(db)); afterEach(() => require('./util').stopRemainingOps(db)); - describe('constructor', function () { - it('should not corrupt options', function (done) { + describe('constructor', function() { + it('should not corrupt options', function(done) { const opts = {}; const query = new Query({}, opts); assert.notEqual(opts, query._mongooseOptions); @@ -60,30 +60,30 @@ describe('Query', function () { }); }); - describe('select', function () { - it('(object)', function (done) { + describe('select', function() { + it('(object)', function(done) { const query = new Query({}); query.select({ a: 1, b: 1, c: 0 }); assert.deepEqual(query._fields, { a: 1, b: 1, c: 0 }); done(); }); - it('(string)', function (done) { + it('(string)', function(done) { const query = new Query({}); query.select(' a b -c '); assert.deepEqual(query._fields, { a: 1, b: 1, c: 0 }); done(); }); - it('("a","b","c")', function (done) { - assert.throws(function () { + it('("a","b","c")', function(done) { + assert.throws(function() { const query = new Query({}); query.select('a', 'b', 'c'); }, /Invalid select/); done(); }); - it('should not overwrite fields set in prior calls', function (done) { + it('should not overwrite fields set in prior calls', function(done) { const query = new Query({}); query.select('a'); assert.deepEqual(query._fields, { a: 1 }); @@ -96,59 +96,45 @@ describe('Query', function () { done(); }); - it('should remove existing fields from inclusive projection', function (done) { + it('should remove existing fields from inclusive projection', function(done) { const query = new Query({}); - query - .select({ - a: 1, - b: 1, - c: 1, - 'parent1.child1': 1, - 'parent1.child2': 1, - 'parent2.child1': 1, - 'parent2.child2': 1, - }) - .select({ b: 0, d: 1, 'c.child': 0, parent1: 0, 'parent2.child1': 0 }); - assert.deepEqual(query._fields, { + query.select({ a: 1, + b: 1, c: 1, - d: 1, - 'parent2.child2': 1, - }); + 'parent1.child1': 1, + 'parent1.child2': 1, + 'parent2.child1': 1, + 'parent2.child2': 1 + }).select({ b: 0, d: 1, 'c.child': 0, parent1: 0, 'parent2.child1': 0 }); + assert.deepEqual(query._fields, { a: 1, c: 1, d: 1, 'parent2.child2': 1 }); done(); }); - it('should remove existing fields from exclusive projection', function (done) { + it('should remove existing fields from exclusive projection', function(done) { const query = new Query({}); - query - .select({ - a: 0, - b: 0, - c: 0, - 'parent1.child1': 0, - 'parent1.child2': 0, - 'parent2.child1': 0, - 'parent2.child2': 0, - }) - .select({ b: 1, d: 0, 'c.child': 1, parent1: 1, 'parent2.child1': 1 }); - assert.deepEqual(query._fields, { + query.select({ a: 0, + b: 0, c: 0, - d: 0, - 'parent2.child2': 0, - }); + 'parent1.child1': 0, + 'parent1.child2': 0, + 'parent2.child1': 0, + 'parent2.child2': 0 + }).select({ b: 1, d: 0, 'c.child': 1, parent1: 1, 'parent2.child1': 1 }); + assert.deepEqual(query._fields, { a: 0, c: 0, d: 0, 'parent2.child2': 0 }); done(); }); }); - describe('projection() (gh-7384)', function () { - it('gets current projection', function () { + describe('projection() (gh-7384)', function() { + it('gets current projection', function() { const query = new Query({}); query.select('a'); assert.deepEqual(query.projection(), { a: 1 }); }); - it('overwrites current projection', function () { + it('overwrites current projection', function() { const query = new Query({}); query.select('a'); assert.deepEqual(query.projection({ b: 1 }), { b: 1 }); @@ -156,8 +142,8 @@ describe('Query', function () { }); }); - describe('where', function () { - it('works', function (done) { + describe('where', function() { + it('works', function(done) { const query = new Query({}); query.where('name', 'guillermo'); assert.deepEqual(query._conditions, { name: 'guillermo' }); @@ -166,27 +152,27 @@ describe('Query', function () { assert.deepEqual(query._conditions, { name: 'guillermo', a: 'b' }); done(); }); - it('throws if non-string or non-object path is passed', function (done) { + it('throws if non-string or non-object path is passed', function(done) { const query = new Query({}); - assert.throws(function () { + assert.throws(function() { query.where(50); }); - assert.throws(function () { + assert.throws(function() { query.where([]); }); done(); }); - it('does not throw when 0 args passed', function (done) { + it('does not throw when 0 args passed', function(done) { const query = new Query({}); - assert.doesNotThrow(function () { + assert.doesNotThrow(function() { query.where(); }); done(); }); }); - describe('equals', function () { - it('works', function (done) { + describe('equals', function() { + it('works', function(done) { const query = new Query({}); query.where('name').equals('guillermo'); assert.deepEqual(query._conditions, { name: 'guillermo' }); @@ -194,14 +180,14 @@ describe('Query', function () { }); }); - describe('gte', function () { - it('with 2 args', function (done) { + describe('gte', function() { + it('with 2 args', function(done) { const query = new Query({}); query.gte('age', 18); assert.deepEqual(query._conditions, { age: { $gte: 18 } }); done(); }); - it('with 1 arg', function (done) { + it('with 1 arg', function(done) { const query = new Query({}); query.where('age').gte(18); assert.deepEqual(query._conditions, { age: { $gte: 18 } }); @@ -209,14 +195,14 @@ describe('Query', function () { }); }); - describe('gt', function () { - it('with 1 arg', function (done) { + describe('gt', function() { + it('with 1 arg', function(done) { const query = new Query({}); query.where('age').gt(17); assert.deepEqual(query._conditions, { age: { $gt: 17 } }); done(); }); - it('with 2 args', function (done) { + it('with 2 args', function(done) { const query = new Query({}); query.gt('age', 17); assert.deepEqual(query._conditions, { age: { $gt: 17 } }); @@ -224,14 +210,14 @@ describe('Query', function () { }); }); - describe('lte', function () { - it('with 1 arg', function (done) { + describe('lte', function() { + it('with 1 arg', function(done) { const query = new Query({}); query.where('age').lte(65); assert.deepEqual(query._conditions, { age: { $lte: 65 } }); done(); }); - it('with 2 args', function (done) { + it('with 2 args', function(done) { const query = new Query({}); query.lte('age', 65); assert.deepEqual(query._conditions, { age: { $lte: 65 } }); @@ -239,14 +225,14 @@ describe('Query', function () { }); }); - describe('lt', function () { - it('with 1 arg', function (done) { + describe('lt', function() { + it('with 1 arg', function(done) { const query = new Query({}); query.where('age').lt(66); assert.deepEqual(query._conditions, { age: { $lt: 66 } }); done(); }); - it('with 2 args', function (done) { + it('with 2 args', function(done) { const query = new Query({}); query.lt('age', 66); assert.deepEqual(query._conditions, { age: { $lt: 66 } }); @@ -254,9 +240,9 @@ describe('Query', function () { }); }); - describe('combined', function () { - describe('lt and gt', function () { - it('works', function (done) { + describe('combined', function() { + describe('lt and gt', function() { + it('works', function(done) { const query = new Query({}); query.where('age').lt(66).gt(17); assert.deepEqual(query._conditions, { age: { $lt: 66, $gt: 17 } }); @@ -265,26 +251,25 @@ describe('Query', function () { }); }); - describe('tl on one path and gt on another', function () { - it('works', function (done) { + describe('tl on one path and gt on another', function() { + it('works', function(done) { const query = new Query({}); - query.where('age').lt(66).where('height').gt(5); - assert.deepEqual(query._conditions, { - age: { $lt: 66 }, - height: { $gt: 5 }, - }); + query + .where('age').lt(66) + .where('height').gt(5); + assert.deepEqual(query._conditions, { age: { $lt: 66 }, height: { $gt: 5 } }); done(); }); }); - describe('ne', function () { - it('with 1 arg', function (done) { + describe('ne', function() { + it('with 1 arg', function(done) { const query = new Query({}); query.where('age').ne(21); assert.deepEqual(query._conditions, { age: { $ne: 21 } }); done(); }); - it('with 2 args', function (done) { + it('with 2 args', function(done) { const query = new Query({}); query.ne('age', 21); assert.deepEqual(query._conditions, { age: { $ne: 21 } }); @@ -292,26 +277,26 @@ describe('Query', function () { }); }); - describe('in', function () { - it('with 1 arg', function (done) { + describe('in', function() { + it('with 1 arg', function(done) { const query = new Query({}); query.where('age').in([21, 25, 30]); assert.deepEqual(query._conditions, { age: { $in: [21, 25, 30] } }); done(); }); - it('with 2 args', function (done) { + it('with 2 args', function(done) { const query = new Query({}); query.in('age', [21, 25, 30]); assert.deepEqual(query._conditions, { age: { $in: [21, 25, 30] } }); done(); }); - it('where a non-array value no via where', function (done) { + it('where a non-array value no via where', function(done) { const query = new Query({}); query.in('age', 21); assert.deepEqual(query._conditions, { age: { $in: 21 } }); done(); }); - it('where a non-array value via where', function (done) { + it('where a non-array value via where', function(done) { const query = new Query({}); query.where('age').in(21); assert.deepEqual(query._conditions, { age: { $in: 21 } }); @@ -319,26 +304,26 @@ describe('Query', function () { }); }); - describe('nin', function () { - it('with 1 arg', function (done) { + describe('nin', function() { + it('with 1 arg', function(done) { const query = new Query({}); query.where('age').nin([21, 25, 30]); assert.deepEqual(query._conditions, { age: { $nin: [21, 25, 30] } }); done(); }); - it('with 2 args', function (done) { + it('with 2 args', function(done) { const query = new Query({}); query.nin('age', [21, 25, 30]); assert.deepEqual(query._conditions, { age: { $nin: [21, 25, 30] } }); done(); }); - it('with a non-array value not via where', function (done) { + it('with a non-array value not via where', function(done) { const query = new Query({}); query.nin('age', 21); assert.deepEqual(query._conditions, { age: { $nin: 21 } }); done(); }); - it('with a non-array value via where', function (done) { + it('with a non-array value via where', function(done) { const query = new Query({}); query.where('age').nin(21); assert.deepEqual(query._conditions, { age: { $nin: 21 } }); @@ -346,26 +331,26 @@ describe('Query', function () { }); }); - describe('mod', function () { - it('not via where, where [a, b] param', function (done) { + describe('mod', function() { + it('not via where, where [a, b] param', function(done) { const query = new Query({}); query.mod('age', [5, 2]); assert.deepEqual(query._conditions, { age: { $mod: [5, 2] } }); done(); }); - it('not via where, where a and b params', function (done) { + it('not via where, where a and b params', function(done) { const query = new Query({}); query.mod('age', 5, 2); assert.deepEqual(query._conditions, { age: { $mod: [5, 2] } }); done(); }); - it('via where, where [a, b] param', function (done) { + it('via where, where [a, b] param', function(done) { const query = new Query({}); query.where('age').mod([5, 2]); assert.deepEqual(query._conditions, { age: { $mod: [5, 2] } }); done(); }); - it('via where, where a and b params', function (done) { + it('via where, where a and b params', function(done) { const query = new Query({}); query.where('age').mod(5, 2); assert.deepEqual(query._conditions, { age: { $mod: [5, 2] } }); @@ -373,169 +358,123 @@ describe('Query', function () { }); }); - describe('near', function () { - it('via where, where { center :[lat, long]} param', function (done) { + describe('near', function() { + it('via where, where { center :[lat, long]} param', function(done) { const query = new Query({}); query.where('checkin').near({ center: [40, -72] }); assert.deepEqual(query._conditions, { checkin: { $near: [40, -72] } }); done(); }); - it('via where, where [lat, long] param', function (done) { + it('via where, where [lat, long] param', function(done) { const query = new Query({}); query.where('checkin').near([40, -72]); assert.deepEqual(query._conditions, { checkin: { $near: [40, -72] } }); done(); }); - it('via where, where lat and long params', function (done) { + it('via where, where lat and long params', function(done) { const query = new Query({}); query.where('checkin').near(40, -72); assert.deepEqual(query._conditions, { checkin: { $near: [40, -72] } }); done(); }); - it('not via where, where [lat, long] param', function (done) { + it('not via where, where [lat, long] param', function(done) { const query = new Query({}); query.near('checkin', [40, -72]); assert.deepEqual(query._conditions, { checkin: { $near: [40, -72] } }); done(); }); - it('not via where, where lat and long params', function (done) { + it('not via where, where lat and long params', function(done) { const query = new Query({}); query.near('checkin', 40, -72); assert.deepEqual(query._conditions, { checkin: { $near: [40, -72] } }); done(); }); - it('via where, where GeoJSON param', function (done) { + it('via where, where GeoJSON param', function(done) { const query = new Query({}); - query - .where('numbers') - .near({ center: { type: 'Point', coordinates: [40, -72] } }); - assert.deepEqual(query._conditions, { - numbers: { - $near: { $geometry: { type: 'Point', coordinates: [40, -72] } }, - }, - }); - assert.doesNotThrow(function () { + query.where('numbers').near({ center: { type: 'Point', coordinates: [40, -72] } }); + assert.deepEqual(query._conditions, { numbers: { $near: { $geometry: { type: 'Point', coordinates: [40, -72] } } } }); + assert.doesNotThrow(function() { query.cast(db.model('Product', productSchema)); }); done(); }); - it('with path, where GeoJSON param', function (done) { + it('with path, where GeoJSON param', function(done) { const query = new Query({}); query.near('loc', { center: { type: 'Point', coordinates: [40, -72] } }); - assert.deepEqual(query._conditions, { - loc: { - $near: { $geometry: { type: 'Point', coordinates: [40, -72] } }, - }, - }); + assert.deepEqual(query._conditions, { loc: { $near: { $geometry: { type: 'Point', coordinates: [40, -72] } } } }); done(); }); }); - describe('nearSphere', function () { - it('via where, where [lat, long] param', function (done) { + describe('nearSphere', function() { + it('via where, where [lat, long] param', function(done) { const query = new Query({}); query.where('checkin').nearSphere([40, -72]); - assert.deepEqual(query._conditions, { - checkin: { $nearSphere: [40, -72] }, - }); + assert.deepEqual(query._conditions, { checkin: { $nearSphere: [40, -72] } }); done(); }); - it('via where, where lat and long params', function (done) { + it('via where, where lat and long params', function(done) { const query = new Query({}); query.where('checkin').nearSphere(40, -72); - assert.deepEqual(query._conditions, { - checkin: { $nearSphere: [40, -72] }, - }); + assert.deepEqual(query._conditions, { checkin: { $nearSphere: [40, -72] } }); done(); }); - it('not via where, where [lat, long] param', function (done) { + it('not via where, where [lat, long] param', function(done) { const query = new Query({}); query.nearSphere('checkin', [40, -72]); - assert.deepEqual(query._conditions, { - checkin: { $nearSphere: [40, -72] }, - }); + assert.deepEqual(query._conditions, { checkin: { $nearSphere: [40, -72] } }); done(); }); - it('not via where, where lat and long params', function (done) { + it('not via where, where lat and long params', function(done) { const query = new Query({}); query.nearSphere('checkin', 40, -72); - assert.deepEqual(query._conditions, { - checkin: { $nearSphere: [40, -72] }, - }); + assert.deepEqual(query._conditions, { checkin: { $nearSphere: [40, -72] } }); done(); }); - it('via where, with object', function (done) { + it('via where, with object', function(done) { const query = new Query({}); query.where('checkin').nearSphere({ center: [20, 23], maxDistance: 2 }); - assert.deepEqual(query._conditions, { - checkin: { $nearSphere: [20, 23], $maxDistance: 2 }, - }); + assert.deepEqual(query._conditions, { checkin: { $nearSphere: [20, 23], $maxDistance: 2 } }); done(); }); - it('via where, where GeoJSON param', function (done) { + it('via where, where GeoJSON param', function(done) { const query = new Query({}); - query - .where('numbers') - .nearSphere({ center: { type: 'Point', coordinates: [40, -72] } }); - assert.deepEqual(query._conditions, { - numbers: { - $nearSphere: { $geometry: { type: 'Point', coordinates: [40, -72] } }, - }, - }); - assert.doesNotThrow(function () { + query.where('numbers').nearSphere({ center: { type: 'Point', coordinates: [40, -72] } }); + assert.deepEqual(query._conditions, { numbers: { $nearSphere: { $geometry: { type: 'Point', coordinates: [40, -72] } } } }); + assert.doesNotThrow(function() { query.cast(db.model('Product', productSchema)); }); done(); }); - it('with path, with GeoJSON', function (done) { + it('with path, with GeoJSON', function(done) { const query = new Query({}); - query.nearSphere('numbers', { - center: { type: 'Point', coordinates: [40, -72] }, - }); - assert.deepEqual(query._conditions, { - numbers: { - $nearSphere: { $geometry: { type: 'Point', coordinates: [40, -72] } }, - }, - }); - assert.doesNotThrow(function () { + query.nearSphere('numbers', { center: { type: 'Point', coordinates: [40, -72] } }); + assert.deepEqual(query._conditions, { numbers: { $nearSphere: { $geometry: { type: 'Point', coordinates: [40, -72] } } } }); + assert.doesNotThrow(function() { query.cast(db.model('Product', productSchema)); }); done(); }); }); - describe('maxDistance', function () { - it('via where', function (done) { + describe('maxDistance', function() { + it('via where', function(done) { const query = new Query({}); query.where('checkin').near([40, -72]).maxDistance(1); - assert.deepEqual(query._conditions, { - checkin: { $near: [40, -72], $maxDistance: 1 }, - }); + assert.deepEqual(query._conditions, { checkin: { $near: [40, -72], $maxDistance: 1 } }); done(); }); }); - describe('within', function () { - describe('box', function () { - it('via where', function (done) { + describe('within', function() { + describe('box', function() { + it('via where', function(done) { const query = new Query({}); - query - .where('gps') - .within() - .box({ ll: [5, 25], ur: [10, 30] }); - const match = { - gps: { - $within: { - $box: [ - [5, 25], - [10, 30], - ], - }, - }, - }; + query.where('gps').within().box({ ll: [5, 25], ur: [10, 30] }); + const match = { gps: { $within: { $box: [[5, 25], [10, 30]] } } }; if (Query.use$geoWithin) { match.gps.$geoWithin = match.gps.$within; delete match.gps.$within; @@ -543,19 +482,10 @@ describe('Query', function () { assert.deepEqual(query._conditions, match); done(); }); - it('via where, no object', function (done) { + it('via where, no object', function(done) { const query = new Query({}); query.where('gps').within().box([5, 25], [10, 30]); - const match = { - gps: { - $within: { - $box: [ - [5, 25], - [10, 30], - ], - }, - }, - }; + const match = { gps: { $within: { $box: [[5, 25], [10, 30]] } } }; if (Query.use$geoWithin) { match.gps.$geoWithin = match.gps.$within; delete match.gps.$within; @@ -565,13 +495,10 @@ describe('Query', function () { }); }); - describe('center', function () { - it('via where', function (done) { + describe('center', function() { + it('via where', function(done) { const query = new Query({}); - query - .where('gps') - .within() - .center({ center: [5, 25], radius: 5 }); + query.where('gps').within().center({ center: [5, 25], radius: 5 }); const match = { gps: { $within: { $center: [[5, 25], 5] } } }; if (Query.use$geoWithin) { match.gps.$geoWithin = match.gps.$within; @@ -582,13 +509,10 @@ describe('Query', function () { }); }); - describe('centerSphere', function () { - it('via where', function (done) { + describe('centerSphere', function() { + it('via where', function(done) { const query = new Query({}); - query - .where('gps') - .within() - .centerSphere({ center: [5, 25], radius: 5 }); + query.where('gps').within().centerSphere({ center: [5, 25], radius: 5 }); const match = { gps: { $within: { $centerSphere: [[5, 25], 5] } } }; if (Query.use$geoWithin) { match.gps.$geoWithin = match.gps.$within; @@ -599,30 +523,11 @@ describe('Query', function () { }); }); - describe('polygon', function () { - it('via where', function (done) { + describe('polygon', function() { + it('via where', function(done) { const query = new Query({}); - query - .where('gps') - .within() - .polygon({ - a: { x: 10, y: 20 }, - b: { x: 15, y: 25 }, - c: { x: 20, y: 20 }, - }); - const match = { - gps: { - $within: { - $polygon: [ - { - a: { x: 10, y: 20 }, - b: { x: 15, y: 25 }, - c: { x: 20, y: 20 }, - }, - ], - }, - }, - }; + query.where('gps').within().polygon({ a: { x: 10, y: 20 }, b: { x: 15, y: 25 }, c: { x: 20, y: 20 } }); + const match = { gps: { $within: { $polygon: [{ a: { x: 10, y: 20 }, b: { x: 15, y: 25 }, c: { x: 20, y: 20 } }] } } }; if (Query.use$geoWithin) { match.gps.$geoWithin = match.gps.$within; delete match.gps.$within; @@ -633,27 +538,27 @@ describe('Query', function () { }); }); - describe('exists', function () { - it('0 args via where', function (done) { + describe('exists', function() { + it('0 args via where', function(done) { const query = new Query({}); query.where('username').exists(); assert.deepEqual(query._conditions, { username: { $exists: true } }); done(); }); - it('1 arg via where', function (done) { + it('1 arg via where', function(done) { const query = new Query({}); query.where('username').exists(false); assert.deepEqual(query._conditions, { username: { $exists: false } }); done(); }); - it('where 1 argument not via where', function (done) { + it('where 1 argument not via where', function(done) { const query = new Query({}); query.exists('username'); assert.deepEqual(query._conditions, { username: { $exists: true } }); done(); }); - it('where 2 args not via where', function (done) { + it('where 2 args not via where', function(done) { const query = new Query({}); query.exists('username', false); assert.deepEqual(query._conditions, { username: { $exists: false } }); @@ -661,33 +566,29 @@ describe('Query', function () { }); }); - describe('all', function () { - it('via where', function (done) { + describe('all', function() { + it('via where', function(done) { const query = new Query({}); query.where('pets').all(['dog', 'cat', 'ferret']); - assert.deepEqual(query._conditions, { - pets: { $all: ['dog', 'cat', 'ferret'] }, - }); + assert.deepEqual(query._conditions, { pets: { $all: ['dog', 'cat', 'ferret'] } }); done(); }); - it('not via where', function (done) { + it('not via where', function(done) { const query = new Query({}); query.all('pets', ['dog', 'cat', 'ferret']); - assert.deepEqual(query._conditions, { - pets: { $all: ['dog', 'cat', 'ferret'] }, - }); + assert.deepEqual(query._conditions, { pets: { $all: ['dog', 'cat', 'ferret'] } }); done(); }); }); - describe('find', function () { - it('strict array equivalence condition v', function (done) { + describe('find', function() { + it('strict array equivalence condition v', function(done) { const query = new Query({}); query.find({ pets: ['dog', 'cat', 'ferret'] }); assert.deepEqual(query._conditions, { pets: ['dog', 'cat', 'ferret'] }); done(); }); - it('with no args', function (done) { + it('with no args', function(done) { let threw = false; const q = new Query({}); @@ -701,9 +602,9 @@ describe('Query', function () { done(); }); - it('works with overwriting previous object args (1176)', function (done) { + it('works with overwriting previous object args (1176)', function(done) { const q = new Query({}); - assert.doesNotThrow(function () { + assert.doesNotThrow(function() { q.find({ age: { $lt: 30 } }); q.find({ age: 20 }); // overwrite }); @@ -712,14 +613,14 @@ describe('Query', function () { }); }); - describe('size', function () { - it('via where', function (done) { + describe('size', function() { + it('via where', function(done) { const query = new Query({}); query.where('collection').size(5); assert.deepEqual(query._conditions, { collection: { $size: 5 } }); done(); }); - it('not via where', function (done) { + it('not via where', function(done) { const query = new Query({}); query.size('collection', 5); assert.deepEqual(query._conditions, { collection: { $size: 5 } }); @@ -727,74 +628,74 @@ describe('Query', function () { }); }); - describe('slice', function () { - it('where and positive limit param', function (done) { + describe('slice', function() { + it('where and positive limit param', function(done) { const query = new Query({}); query.where('collection').slice(5); assert.deepEqual(query._fields, { collection: { $slice: 5 } }); done(); }); - it('where just negative limit param', function (done) { + it('where just negative limit param', function(done) { const query = new Query({}); query.where('collection').slice(-5); assert.deepEqual(query._fields, { collection: { $slice: -5 } }); done(); }); - it('where [skip, limit] param', function (done) { + it('where [skip, limit] param', function(done) { const query = new Query({}); query.where('collection').slice([14, 10]); // Return the 15th through 25th assert.deepEqual(query._fields, { collection: { $slice: [14, 10] } }); done(); }); - it('where skip and limit params', function (done) { + it('where skip and limit params', function(done) { const query = new Query({}); query.where('collection').slice(14, 10); // Return the 15th through 25th assert.deepEqual(query._fields, { collection: { $slice: [14, 10] } }); done(); }); - it('where just positive limit param', function (done) { + it('where just positive limit param', function(done) { const query = new Query({}); query.where('collection').slice(5); assert.deepEqual(query._fields, { collection: { $slice: 5 } }); done(); }); - it('where just negative limit param', function (done) { + it('where just negative limit param', function(done) { const query = new Query({}); query.where('collection').slice(-5); assert.deepEqual(query._fields, { collection: { $slice: -5 } }); done(); }); - it('where the [skip, limit] param', function (done) { + it('where the [skip, limit] param', function(done) { const query = new Query({}); query.where('collection').slice([14, 10]); // Return the 15th through 25th assert.deepEqual(query._fields, { collection: { $slice: [14, 10] } }); done(); }); - it('where the skip and limit params', function (done) { + it('where the skip and limit params', function(done) { const query = new Query({}); query.where('collection').slice(14, 10); // Return the 15th through 25th assert.deepEqual(query._fields, { collection: { $slice: [14, 10] } }); done(); }); - it('not via where, with just positive limit param', function (done) { + it('not via where, with just positive limit param', function(done) { const query = new Query({}); query.slice('collection', 5); assert.deepEqual(query._fields, { collection: { $slice: 5 } }); done(); }); - it('not via where, where just negative limit param', function (done) { + it('not via where, where just negative limit param', function(done) { const query = new Query({}); query.slice('collection', -5); assert.deepEqual(query._fields, { collection: { $slice: -5 } }); done(); }); - it('not via where, where [skip, limit] param', function (done) { + it('not via where, where [skip, limit] param', function(done) { const query = new Query({}); query.slice('collection', [14, 10]); // Return the 15th through 25th assert.deepEqual(query._fields, { collection: { $slice: [14, 10] } }); done(); }); - it('not via where, where skip and limit params', function (done) { + it('not via where, where skip and limit params', function(done) { const query = new Query({}); query.slice('collection', 14, 10); // Return the 15th through 25th assert.deepEqual(query._fields, { collection: { $slice: [14, 10] } }); @@ -802,55 +703,45 @@ describe('Query', function () { }); }); - describe('elemMatch', function () { - describe('not via where', function () { - it('works', function (done) { + describe('elemMatch', function() { + describe('not via where', function() { + it('works', function(done) { const query = new Query({}); query.elemMatch('comments', { author: 'bnoguchi', votes: { $gte: 5 } }); - assert.deepEqual(query._conditions, { - comments: { $elemMatch: { author: 'bnoguchi', votes: { $gte: 5 } } }, - }); + assert.deepEqual(query._conditions, { comments: { $elemMatch: { author: 'bnoguchi', votes: { $gte: 5 } } } }); done(); }); - it('where block notation', function (done) { + it('where block notation', function(done) { const query = new Query({}); - query.elemMatch('comments', function (elem) { + query.elemMatch('comments', function(elem) { elem.where('author', 'bnoguchi'); elem.where('votes').gte(5); }); - assert.deepEqual(query._conditions, { - comments: { $elemMatch: { author: 'bnoguchi', votes: { $gte: 5 } } }, - }); + assert.deepEqual(query._conditions, { comments: { $elemMatch: { author: 'bnoguchi', votes: { $gte: 5 } } } }); done(); }); }); - describe('via where', function () { - it('works', function (done) { + describe('via where', function() { + it('works', function(done) { const query = new Query({}); - query - .where('comments') - .elemMatch({ author: 'bnoguchi', votes: { $gte: 5 } }); - assert.deepEqual(query._conditions, { - comments: { $elemMatch: { author: 'bnoguchi', votes: { $gte: 5 } } }, - }); + query.where('comments').elemMatch({ author: 'bnoguchi', votes: { $gte: 5 } }); + assert.deepEqual(query._conditions, { comments: { $elemMatch: { author: 'bnoguchi', votes: { $gte: 5 } } } }); done(); }); - it('where block notation', function (done) { + it('where block notation', function(done) { const query = new Query({}); - query.where('comments').elemMatch(function (elem) { + query.where('comments').elemMatch(function(elem) { elem.where('author', 'bnoguchi'); elem.where('votes').gte(5); }); - assert.deepEqual(query._conditions, { - comments: { $elemMatch: { author: 'bnoguchi', votes: { $gte: 5 } } }, - }); + assert.deepEqual(query._conditions, { comments: { $elemMatch: { author: 'bnoguchi', votes: { $gte: 5 } } } }); done(); }); }); }); - describe('$where', function () { - it('function arg', function (done) { + describe('$where', function() { + it('function arg', function(done) { const query = new Query({}); function filter() { @@ -861,25 +752,23 @@ describe('Query', function () { assert.deepEqual(query._conditions, { $where: filter }); done(); }); - it('string arg', function (done) { + it('string arg', function(done) { const query = new Query({}); query.$where('this.lastName === this.firstName'); - assert.deepEqual(query._conditions, { - $where: 'this.lastName === this.firstName', - }); + assert.deepEqual(query._conditions, { $where: 'this.lastName === this.firstName' }); done(); }); }); - describe('limit', function () { - it('works', function (done) { + describe('limit', function() { + it('works', function(done) { const query = new Query({}); query.limit(5); assert.strictEqual(query.options.limit, 5); done(); }); - it('with string limit (gh-11017)', function () { + it('with string limit (gh-11017)', function() { const query = new Query({}); query.limit('5'); assert.strictEqual(query.options.limit, 5); @@ -888,8 +777,8 @@ describe('Query', function () { }); }); - describe('skip', function () { - it('works', function (done) { + describe('skip', function() { + it('works', function(done) { const query = new Query({}); query.skip(9); assert.equal(query.options.skip, 9); @@ -897,8 +786,8 @@ describe('Query', function () { }); }); - describe('sort', function () { - it('works', function (done) { + describe('sort', function() { + it('works', function(done) { let query = new Query({}); query.sort('a -c b'); assert.deepEqual(query.options.sort, { a: 1, c: -1, b: 1 }); @@ -923,10 +812,7 @@ describe('Query', function () { } assert.ok(e, 'uh oh. no error was thrown'); - assert.equal( - e.message, - 'Invalid sort() argument, must be array of arrays' - ); + assert.equal(e.message, 'Invalid sort() argument, must be array of arrays'); e = undefined; try { @@ -940,12 +826,12 @@ describe('Query', function () { }); }); - describe('or', function () { - it('works', function (done) { + describe('or', function() { + it('works', function(done) { const query = new Query(); query.find({ $or: [{ x: 1 }, { x: 2 }] }); assert.equal(query._conditions.$or.length, 2); - query.or([{ y: "We're under attack" }, { z: 47 }]); + query.or([{ y: 'We\'re under attack' }, { z: 47 }]); assert.equal(query._conditions.$or.length, 4); assert.equal(query._conditions.$or[3].z, 47); query.or({ z: 'phew' }); @@ -956,27 +842,27 @@ describe('Query', function () { }); }); - describe('and', function () { - it('works', function (done) { + describe('and', function() { + it('works', function(done) { const query = new Query(); query.find({ $and: [{ x: 1 }, { y: 2 }] }); assert.equal(query._conditions.$and.length, 2); - query.and([{ z: "We're under attack" }, { w: 47 }]); + query.and([{ z: 'We\'re under attack' }, { w: 47 }]); assert.equal(query._conditions.$and.length, 4); assert.equal(query._conditions.$and[3].w, 47); query.and({ a: 'phew' }); assert.equal(query._conditions.$and.length, 5); assert.equal(query._conditions.$and[0].x, 1); assert.equal(query._conditions.$and[1].y, 2); - assert.equal(query._conditions.$and[2].z, "We're under attack"); + assert.equal(query._conditions.$and[2].z, 'We\'re under attack'); assert.equal(query._conditions.$and[3].w, 47); assert.equal(query._conditions.$and[4].a, 'phew'); done(); }); }); - describe('populate', function () { - it('converts to PopulateOptions objects', function (done) { + describe('populate', function() { + it('converts to PopulateOptions objects', function(done) { const q = new Query({}); const o = { path: 'yellow.brick', @@ -985,20 +871,20 @@ describe('Query', function () { model: undefined, options: undefined, _docs: {}, - _childDocs: [], + _childDocs: [] }; q.populate(o); assert.deepEqual(o, q._mongooseOptions.populate['yellow.brick']); done(); }); - it('overwrites duplicate paths', function (done) { + it('overwrites duplicate paths', function(done) { const q = new Query({}); let o = { path: 'yellow.brick', match: { bricks: { $lt: 1000 } }, _docs: {}, - _childDocs: [], + _childDocs: [] }; q.populate(Object.assign({}, o)); assert.equal(Object.keys(q._mongooseOptions.populate).length, 1); @@ -1008,78 +894,80 @@ describe('Query', function () { o = { path: 'yellow.brick', _docs: {}, - _childDocs: [], + _childDocs: [] }; assert.equal(Object.keys(q._mongooseOptions.populate).length, 1); assert.deepEqual(q._mongooseOptions.populate['yellow.brick'], o); done(); }); - it('accepts space delimited strings', function (done) { + it('accepts space delimited strings', function(done) { const q = new Query({}); q.populate('yellow.brick dirt'); assert.equal(Object.keys(q._mongooseOptions.populate).length, 2); assert.deepEqual(q._mongooseOptions.populate['yellow.brick'], { path: 'yellow.brick', _docs: {}, - _childDocs: [], + _childDocs: [] }); assert.deepEqual(q._mongooseOptions.populate['dirt'], { path: 'dirt', _docs: {}, - _childDocs: [], + _childDocs: [] }); done(); }); }); - describe('casting', function () { - it('to an array of mixed', function (done) { + describe('casting', function() { + it('to an array of mixed', function(done) { const query = new Query({}); const Product = db.model('Product', productSchema); - const params = { - _id: new DocumentObjectId(), - tags: { $in: [4, 8, 15, 16] }, - }; + const params = { _id: new DocumentObjectId(), tags: { $in: [4, 8, 15, 16] } }; query.cast(Product, params); assert.deepEqual(params.tags.$in, [4, 8, 15, 16]); done(); }); - it("doesn't wipe out $in (gh-6439)", async function () { - const embeddedSchema = new Schema( - { - name: String, - }, - { _id: false } - ); + it('doesn\'t wipe out $in (gh-6439)', async function() { + const embeddedSchema = new Schema({ + name: String + }, { _id: false }); const catSchema = new Schema({ name: String, - props: [embeddedSchema], + props: [embeddedSchema] }); const Cat = db.model('Cat', catSchema); const kitty = new Cat({ name: 'Zildjian', - props: [{ name: 'invalid' }, { name: 'abc' }, { name: 'def' }], + props: [ + { name: 'invalid' }, + { name: 'abc' }, + { name: 'def' } + ] }); + await kitty.save(); const cond = { _id: kitty._id }; const update = { $pull: { props: { - $in: [{ name: 'invalid' }, { name: 'def' }], - }, - }, + $in: [ + { name: 'invalid' }, + { name: 'def' } + ] + } + } }; await Cat.updateOne(cond, update); const found = await Cat.findOne(cond); assert.strictEqual(found.props[0].name, 'abc'); }); - it('find $ne should not cast single value to array for schematype of Array', function (done) { + it('find $ne should not cast single value to array for schematype of Array', function(done) { const query = new Query({}); const Product = db.model('Product', productSchema); const Comment = db.model('Comment', commentSchema); @@ -1093,7 +981,7 @@ describe('Query', function () { ids: { $ne: id }, comments: { $ne: comment }, strings: { $ne: 'Hi there' }, - numbers: { $ne: 10000 }, + numbers: { $ne: 10000 } }; query.cast(Product, params); @@ -1123,12 +1011,12 @@ describe('Query', function () { done(); }); - it('subdocument array with $ne: null should not throw', function (done) { + it('subdocument array with $ne: null should not throw', function(done) { const query = new Query({}); const Product = db.model('Product', productSchema); const params = { - comments: { $ne: null }, + comments: { $ne: null } }; query.cast(Product, params); @@ -1136,7 +1024,7 @@ describe('Query', function () { done(); }); - it('find should not cast single value to array for schematype of Array', function (done) { + it('find should not cast single value to array for schematype of Array', function(done) { const query = new Query({}); const Product = db.model('Product', productSchema); const Comment = db.model('Comment', commentSchema); @@ -1150,7 +1038,7 @@ describe('Query', function () { ids: id, comments: comment, strings: 'Hi there', - numbers: 10000, + numbers: 10000 }; query.cast(Product, params); @@ -1180,13 +1068,10 @@ describe('Query', function () { done(); }); - it('an $elemMatch with $in works (gh-1100)', function (done) { + it('an $elemMatch with $in works (gh-1100)', function(done) { const query = new Query({}); const Product = db.model('Product', productSchema); - const ids = [ - String(new DocumentObjectId()), - String(new DocumentObjectId()), - ]; + const ids = [String(new DocumentObjectId()), String(new DocumentObjectId())]; const params = { ids: { $elemMatch: { $in: ids } } }; query.cast(Product, params); assert.ok(params.ids.$elemMatch.$in[0] instanceof DocumentObjectId); @@ -1196,7 +1081,7 @@ describe('Query', function () { done(); }); - it('inequality operators for an array', function (done) { + it('inequality operators for an array', function(done) { const query = new Query({}); const Product = db.model('Product', productSchema); const Comment = db.model('Comment', commentSchema); @@ -1209,7 +1094,7 @@ describe('Query', function () { ids: { $gt: id }, comments: { $gt: comment }, strings: { $gt: 'Hi there' }, - numbers: { $gt: 10000 }, + numbers: { $gt: 10000 } }; query.cast(Product, params); @@ -1221,8 +1106,8 @@ describe('Query', function () { }); }); - describe('distinct', function () { - it('op', function () { + describe('distinct', function() { + it('op', function() { const q = new Query({}); q.distinct('blah'); @@ -1231,14 +1116,14 @@ describe('Query', function () { }); }); - describe('findOne', function () { - it('sets the op', function (done) { + describe('findOne', function() { + it('sets the op', function(done) { const Product = db.model('Product', productSchema); const prod = new Product({}); const q = new Query(prod.collection, {}, Product).distinct(); // use a timeout here because we have to wait for the connection to start // before any ops will get set - setTimeout(function () { + setTimeout(function() { assert.equal(q.op, 'distinct'); q.findOne(); assert.equal(q.op, 'findOne'); @@ -1246,25 +1131,23 @@ describe('Query', function () { }, 50); }); - it('works as a promise', function (done) { + it('works as a promise', function(done) { const Product = db.model('Product', productSchema); const promise = Product.findOne(); - promise.then( - function () { - done(); - }, - function (err) { - assert.ifError(err); - } - ); + promise.then(function() { + done(); + }, function(err) { + assert.ifError(err); + }); }); }); - describe('deleteOne/deleteMany', function () { - it('handles deleteOne', async function () { + describe('deleteOne/deleteMany', function() { + it('handles deleteOne', async function() { const M = db.model('Person', new Schema({ name: 'String' })); + await M.deleteMany({}); await M.create([{ name: 'Eddard Stark' }, { name: 'Robb Stark' }]); @@ -1274,9 +1157,10 @@ describe('Query', function () { assert.equal(count, 1); }); - it('handles deleteMany', async function () { + it('handles deleteMany', async function() { const M = db.model('Person', new Schema({ name: 'String' })); + await M.deleteMany({}); await M.create([{ name: 'Eddard Stark' }, { name: 'Robb Stark' }]); @@ -1287,41 +1171,36 @@ describe('Query', function () { }); }); - describe('remove', function () { - it('handles cast errors async', function (done) { + describe('remove', function() { + it('handles cast errors async', function(done) { const Product = db.model('Product', productSchema); - assert.doesNotThrow(function () { - Product.where({ numbers: [[[]]] }).deleteMany(function (err) { + assert.doesNotThrow(function() { + Product.where({ numbers: [[[]]] }).deleteMany(function(err) { assert.ok(err); done(); }); }); }); - it('supports a single conditions arg', function (done) { + it('supports a single conditions arg', function(done) { const Product = db.model('Product', productSchema); - Product.create({ strings: ['remove-single-condition'] }).then( - function () { - const q = Product.where().deleteMany({ - strings: 'remove-single-condition', - }); - assert.ok(q instanceof mongoose.Query); - done(); - }, - done - ); + Product.create({ strings: ['remove-single-condition'] }).then(function() { + const q = Product.where().deleteMany({ strings: 'remove-single-condition' }); + assert.ok(q instanceof mongoose.Query); + done(); + }, done); }); - it('supports a single callback arg', function (done) { + it('supports a single callback arg', function(done) { const Product = db.model('Product', productSchema); const val = 'remove-single-callback'; - Product.create({ strings: [val] }).then(function () { - Product.where({ strings: val }).deleteMany(function (err) { + Product.create({ strings: [val] }).then(function() { + Product.where({ strings: val }).deleteMany(function(err) { assert.ifError(err); - Product.findOne({ strings: val }, function (err, doc) { + Product.findOne({ strings: val }, function(err, doc) { assert.ifError(err); assert.ok(!doc); done(); @@ -1330,14 +1209,14 @@ describe('Query', function () { }, done); }); - it('supports conditions and callback args', function (done) { + it('supports conditions and callback args', function(done) { const Product = db.model('Product', productSchema); const val = 'remove-cond-and-callback'; - Product.create({ strings: [val] }).then(function () { - Product.where().deleteMany({ strings: val }, function (err) { + Product.create({ strings: [val] }).then(function() { + Product.where().deleteMany({ strings: val }, function(err) { assert.ifError(err); - Product.findOne({ strings: val }, function (err, doc) { + Product.findOne({ strings: val }, function(err, doc) { assert.ifError(err); assert.ok(!doc); done(); @@ -1347,44 +1226,41 @@ describe('Query', function () { }); }); - describe('querying/updating with model instance containing embedded docs should work (#454)', function () { - it('works', function (done) { + describe('querying/updating with model instance containing embedded docs should work (#454)', function() { + it('works', function(done) { const Product = db.model('Product', productSchema); const proddoc = { comments: [{ text: 'hello' }] }; const prod2doc = { comments: [{ text: 'goodbye' }] }; const prod = new Product(proddoc); - prod.save(function (err) { + prod.save(function(err) { assert.ifError(err); - Product.findOne({ _id: prod._id }, function (err, product) { + Product.findOne({ _id: prod._id }, function(err, product) { assert.ifError(err); assert.equal(product.comments.length, 1); assert.equal(product.comments[0].text, 'hello'); - Product.updateOne({ _id: prod._id }, prod2doc, function (err) { + Product.updateOne({ _id: prod._id }, prod2doc, function(err) { assert.ifError(err); - Product.collection.findOne( - { _id: product._id }, - function (err, doc) { - assert.ifError(err); - assert.equal(doc.comments.length, 1); - // ensure hidden private props were not saved to db - assert.ok(!doc.comments[0].hasOwnProperty('parentArry')); - assert.equal(doc.comments[0].text, 'goodbye'); - done(); - } - ); + Product.collection.findOne({ _id: product._id }, function(err, doc) { + assert.ifError(err); + assert.equal(doc.comments.length, 1); + // ensure hidden private props were not saved to db + assert.ok(!doc.comments[0].hasOwnProperty('parentArry')); + assert.equal(doc.comments[0].text, 'goodbye'); + done(); + }); }); }); }); }); }); - describe('optionsForExec', function () { - it('should retain key order', function (done) { + describe('optionsForExec', function() { + it('should retain key order', function(done) { // this is important for query hints const hint = { x: 1, y: 1, z: 1 }; const a = JSON.stringify({ hint: hint }); @@ -1397,7 +1273,7 @@ describe('Query', function () { done(); }); - it('applies schema-level writeConcern option', function (done) { + it('applies schema-level writeConcern option', function(done) { const q = new Query(); q.j(true); @@ -1405,20 +1281,20 @@ describe('Query', function () { const options = q._optionsForExec({ schema: { options: { - writeConcern: { w: 'majority' }, - }, - }, + writeConcern: { w: 'majority' } + } + } }); assert.deepEqual(options, { writeConcern: { w: 'majority', - j: true, - }, + j: true + } }); done(); }); - it('session() (gh-6663)', function (done) { + it('session() (gh-6663)', function(done) { const q = new Query(); const fakeSession = 'foo'; @@ -1426,7 +1302,7 @@ describe('Query', function () { const options = q._optionsForExec(); assert.deepEqual(options, { - session: fakeSession, + session: fakeSession }); done(); }); @@ -1434,9 +1310,9 @@ describe('Query', function () { // Advanced Query options - describe('options', function () { - describe('maxscan', function () { - it('works', function (done) { + describe('options', function() { + describe('maxscan', function() { + it('works', function(done) { const query = new Query({}); query.maxscan(100); assert.equal(query.options.maxScan, 100); @@ -1444,8 +1320,8 @@ describe('Query', function () { }); }); - describe('slaveOk', function () { - it('works', function (done) { + describe('slaveOk', function() { + it('works', function(done) { let query = new Query({}); query.slaveOk(); assert.equal(query.options.slaveOk, true); @@ -1461,8 +1337,8 @@ describe('Query', function () { }); }); - describe('tailable', function () { - it('works', function (done) { + describe('tailable', function() { + it('works', function(done) { let query = new Query({}); query.tailable(); assert.equal(query.options.tailable, true); @@ -1476,7 +1352,7 @@ describe('Query', function () { assert.equal(query.options.tailable, false); done(); }); - it('supports passing the `awaitData` option', function (done) { + it('supports passing the `awaitData` option', function(done) { const query = new Query({}); query.tailable({ awaitData: true }); assert.equal(query.options.tailable, true); @@ -1485,8 +1361,8 @@ describe('Query', function () { }); }); - describe('comment', function () { - it('works', function (done) { + describe('comment', function() { + it('works', function(done) { const query = new Query(); assert.equal(typeof query.comment, 'function'); assert.equal(query.comment('Lowpass is more fun'), query); @@ -1495,14 +1371,11 @@ describe('Query', function () { }); }); - describe('hint', function () { - it('works', function (done) { + describe('hint', function() { + it('works', function(done) { const query2 = new Query({}); query2.hint({ indexAttributeA: 1, indexAttributeB: -1 }); - assert.deepEqual(query2.options.hint, { - indexAttributeA: 1, - indexAttributeB: -1, - }); + assert.deepEqual(query2.options.hint, { indexAttributeA: 1, indexAttributeB: -1 }); const query3 = new Query({}); query3.hint('indexAttributeA_1'); @@ -1512,8 +1385,8 @@ describe('Query', function () { }); }); - describe('snapshot', function () { - it('works', function (done) { + describe('snapshot', function() { + it('works', function(done) { const query = new Query({}); query.snapshot(true); assert.equal(query.options.snapshot, true); @@ -1521,8 +1394,8 @@ describe('Query', function () { }); }); - describe('batchSize', function () { - it('works', function (done) { + describe('batchSize', function() { + it('works', function(done) { const query = new Query({}); query.batchSize(10); assert.equal(query.options.batchSize, 10); @@ -1530,11 +1403,11 @@ describe('Query', function () { }); }); - describe('read', function () { + describe('read', function() { const P = mongoose.mongo.ReadPreference; - describe('without tags', function () { - it('works', function (done) { + describe('without tags', function() { + it('works', function(done) { const query = new Query({}); query.read('primary'); assert.ok(query.options.readPreference instanceof P); @@ -1590,13 +1463,10 @@ describe('Query', function () { }); }); - describe('with tags', function () { - it('works', function (done) { + describe('with tags', function() { + it('works', function(done) { const query = new Query({}); - const tags = [ - { dc: 'sf', s: 1 }, - { dc: 'jp', s: 2 }, - ]; + const tags = [{ dc: 'sf', s: 1 }, { dc: 'jp', s: 2 }]; query.read('pp', tags); assert.ok(query.options.readPreference instanceof P); @@ -1611,39 +1481,36 @@ describe('Query', function () { }); }); - describe('inherits its models schema read option', function () { + describe('inherits its models schema read option', function() { let schema, M, called; - before(function () { + before(function() { schema = new Schema({}, { read: 'p' }); M = mongoose.model('schemaOptionReadPrefWithQuery', schema); }); - it('if not set in query', function (done) { + it('if not set in query', function(done) { const options = M.where()._optionsForExec(M); assert.ok(options.readPreference instanceof P); assert.equal(options.readPreference.mode, 'primary'); done(); }); - it('if set in query', function (done) { + it('if set in query', function(done) { const options = M.where().read('s')._optionsForExec(M); assert.ok(options.readPreference instanceof P); assert.equal(options.readPreference.mode, 'secondary'); done(); }); - it('and sends it though the driver', function (done) { - const options = { - read: 'secondary', - writeConcern: { w: 'majority' }, - }; + it('and sends it though the driver', function(done) { + const options = { read: 'secondary', writeConcern: { w: 'majority' } }; const schema = new Schema({ name: String }, options); const M = db.model('Test', schema); const q = M.find(); // stub the internal query options call const getopts = q._optionsForExec; - q._optionsForExec = function (model) { + q._optionsForExec = function(model) { q._optionsForExec = getopts; const ret = getopts.call(this, model); @@ -1656,7 +1523,7 @@ describe('Query', function () { return ret; }; - q.exec(function (err) { + q.exec(function(err) { if (err) { return done(err); } @@ -1668,8 +1535,8 @@ describe('Query', function () { }); }); - describe('setOptions', function () { - it('works', function (done) { + describe('setOptions', function() { + it('works', function(done) { const q = new Query(); q.setOptions({ thing: 'cat' }); q.setOptions({ populate: ['fans'] }); @@ -1682,11 +1549,7 @@ describe('Query', function () { q.setOptions({ read: ['s', [{ dc: 'eu' }]] }); assert.equal(q.options.thing, 'cat'); - assert.deepEqual(q._mongooseOptions.populate.fans, { - path: 'fans', - _docs: {}, - _childDocs: [], - }); + assert.deepEqual(q._mongooseOptions.populate.fans, { path: 'fans', _docs: {}, _childDocs: [] }); assert.equal(q.options.batchSize, 10); assert.equal(q.options.limit, 4); assert.equal(q.options.skip, 3); @@ -1701,33 +1564,27 @@ describe('Query', function () { const Product = db.model('Product', productSchema); Product.create( { numbers: [3, 4, 5] }, - { strings: 'hi there'.split(' ') }, - function (err, doc1, doc2) { + { strings: 'hi there'.split(' ') }, function(err, doc1, doc2) { assert.ifError(err); - Product.find() - .setOptions({ limit: 1, sort: { _id: -1 }, read: 'n' }) - .exec(function (err, docs) { - assert.ifError(err); - assert.equal(docs.length, 1); - assert.equal(docs[0].id, doc2.id); - done(); - }); - } - ); + Product.find().setOptions({ limit: 1, sort: { _id: -1 }, read: 'n' }).exec(function(err, docs) { + assert.ifError(err); + assert.equal(docs.length, 1); + assert.equal(docs[0].id, doc2.id); + done(); + }); + }); }); - it('populate as array in options (gh-4446)', function (done) { + it('populate as array in options (gh-4446)', function(done) { const q = new Query(); q.setOptions({ populate: [{ path: 'path1' }, { path: 'path2' }] }); - assert.deepEqual(Object.keys(q._mongooseOptions.populate), [ - 'path1', - 'path2', - ]); + assert.deepEqual(Object.keys(q._mongooseOptions.populate), + ['path1', 'path2']); done(); }); }); - describe('getOptions', function () { + describe('getOptions', function() { const q = new Query(); q.limit(10); q.setOptions({ maxTimeMS: 1000 }); @@ -1738,9 +1595,9 @@ describe('Query', function () { assert.strictEqual(opts.maxTimeMS, 1000); }); - describe('bug fixes', function () { - describe('collations', function () { - before(async function () { + describe('bug fixes', function() { + describe('collations', function() { + before(async function() { const _this = this; const version = await start.mongodVersion(); @@ -1750,57 +1607,52 @@ describe('Query', function () { } }); - it('collation support (gh-4839)', function (done) { + it('collation support (gh-4839)', function(done) { const schema = new Schema({ - name: String, + name: String }); const MyModel = db.model('Test', schema); const collation = { locale: 'en_US', strength: 1 }; - MyModel.create([{ name: 'a' }, { name: 'A' }]) - .then(function () { + MyModel.create([{ name: 'a' }, { name: 'A' }]). + then(function() { return MyModel.find({ name: 'a' }).collation(collation); - }) - .then(function (docs) { + }). + then(function(docs) { assert.equal(docs.length, 2); return MyModel.find({ name: 'a' }, null, { collation: collation }); - }) - .then(function (docs) { + }). + then(function(docs) { assert.equal(docs.length, 2); - return MyModel.find({ name: 'a' }, null, { collation: collation }) - .sort({ _id: -1 }) - .cursor() - .next(); - }) - .then(function (doc) { + return MyModel.find({ name: 'a' }, null, { collation: collation }). + sort({ _id: -1 }). + cursor(). + next(); + }). + then(function(doc) { assert.equal(doc.name, 'A'); return MyModel.find({ name: 'a' }); - }) - .then(function (docs) { + }). + then(function(docs) { assert.equal(docs.length, 1); done(); - }) - .catch(done); + }). + catch(done); }); - it('set on schema (gh-5295)', async function () { - await db.db - .collection('tests') - .drop() - .catch((err) => { - if (err.message === 'ns not found') { - return; - } - throw err; - }); + it('set on schema (gh-5295)', async function() { - const schema = new Schema( - { - name: String, - }, - { collation: { locale: 'en_US', strength: 1 } } - ); + await db.db.collection('tests').drop().catch(err => { + if (err.message === 'ns not found') { + return; + } + throw err; + }); + + const schema = new Schema({ + name: String + }, { collation: { locale: 'en_US', strength: 1 } }); const MyModel = db.model('Test', schema, 'tests'); @@ -1812,182 +1664,144 @@ describe('Query', function () { }); }); - describe('gh-1950', function () { - it.skip('ignores sort when passed to count', function (done) { + describe('gh-1950', function() { + it.skip('ignores sort when passed to count', function(done) { const Product = db.model('Product', productSchema); - Product.find() - .sort({ _id: 1 }) - .count({}) - .exec(function (error) { - assert.ifError(error); - done(); - }); + Product.find().sort({ _id: 1 }).count({}).exec(function(error) { + assert.ifError(error); + done(); + }); }); - it('ignores sort when passed to countDocuments', function () { + it('ignores sort when passed to countDocuments', function() { const Product = db.model('Product', productSchema); - return Product.create({}).then(() => - Product.find().sort({ _id: 1 }).countDocuments({}).exec() - ); + return Product.create({}). + then(() => Product.find().sort({ _id: 1 }).countDocuments({}).exec()); }); - it.skip('ignores count when passed to sort', function (done) { + it.skip('ignores count when passed to sort', function(done) { const Product = db.model('Product', productSchema); - Product.find() - .count({}) - .sort({ _id: 1 }) - .exec(function (error) { - assert.ifError(error); - done(); - }); + Product.find().count({}).sort({ _id: 1 }).exec(function(error) { + assert.ifError(error); + done(); + }); }); }); - it('excludes _id when select false and inclusive mode (gh-3010)', function (done) { + it('excludes _id when select false and inclusive mode (gh-3010)', function(done) { const User = db.model('User', { _id: { select: false, type: Schema.Types.ObjectId, - default: () => new mongoose.Types.ObjectId(), + default: () => new mongoose.Types.ObjectId() }, - username: String, + username: String }); - User.create({ username: 'Val' }, function (error, user) { + User.create({ username: 'Val' }, function(error, user) { assert.ifError(error); - User.find({ _id: user._id }) - .select('username') - .exec(function (error, users) { - assert.ifError(error); - assert.equal(users.length, 1); - assert.ok(!users[0]._id); - assert.equal(users[0].username, 'Val'); - done(); - }); + User.find({ _id: user._id }).select('username').exec(function(error, users) { + assert.ifError(error); + assert.equal(users.length, 1); + assert.ok(!users[0]._id); + assert.equal(users[0].username, 'Val'); + done(); + }); }); }); - it('doesnt reverse key order for update docs (gh-3215)', function (done) { + it('doesnt reverse key order for update docs (gh-3215)', function(done) { const Test = db.model('Test', { - arr: [{ date: Date, value: Number }], + arr: [{ date: Date, value: Number }] }); - const q = Test.updateOne( - {}, - { - $push: { - arr: { - $each: [{ date: new Date(), value: 1 }], - $sort: { value: -1, date: -1 }, - }, - }, + const q = Test.updateOne({}, { + $push: { + arr: { + $each: [{ date: new Date(), value: 1 }], + $sort: { value: -1, date: -1 } + } } - ); + }); - assert.deepEqual(Object.keys(q.getUpdate().$push.arr.$sort), [ - 'value', - 'date', - ]); + assert.deepEqual(Object.keys(q.getUpdate().$push.arr.$sort), + ['value', 'date']); done(); }); - it('timestamps with $each (gh-4805)', function (done) { + it('timestamps with $each (gh-4805)', function(done) { const nestedSchema = new Schema({ value: Number }, { timestamps: true }); - const Test = db.model( - 'Test', - new Schema( - { - arr: [nestedSchema], - }, - { timestamps: true } - ) - ); + const Test = db.model('Test', new Schema({ + arr: [nestedSchema] + }, { timestamps: true })); - Test.updateOne( - {}, - { - $push: { - arr: { - $each: [{ value: 1 }], - }, - }, + Test.updateOne({}, { + $push: { + arr: { + $each: [{ value: 1 }] + } } - ).exec(function (error) { + }).exec(function(error) { assert.ifError(error); done(); }); }); - it.skip('allows sort with count (gh-3914)', function (done) { + it.skip('allows sort with count (gh-3914)', function(done) { const Post = db.model('BlogPost', { - title: String, + title: String }); - Post.count({}) - .sort({ title: 1 }) - .exec(function (error, count) { - assert.ifError(error); - assert.strictEqual(count, 0); - done(); - }); + Post.count({}).sort({ title: 1 }).exec(function(error, count) { + assert.ifError(error); + assert.strictEqual(count, 0); + done(); + }); }); - it.skip('allows sort with select (gh-3914)', function (done) { + it.skip('allows sort with select (gh-3914)', function(done) { const Post = db.model('BlogPost', { - title: String, + title: String }); - Post.count({}) - .select({ _id: 0 }) - .exec(function (error, count) { - assert.ifError(error); - assert.strictEqual(count, 0); - done(); - }); + Post.count({}).select({ _id: 0 }).exec(function(error, count) { + assert.ifError(error); + assert.strictEqual(count, 0); + done(); + }); }); - it('handles nested $ (gh-3265)', function (done) { + it('handles nested $ (gh-3265)', function(done) { const Post = db.model('BlogPost', { title: String, - answers: [ - { - details: String, - stats: { - votes: Number, - count: Number, - }, - }, - ], + answers: [{ + details: String, + stats: { + votes: Number, + count: Number + } + }] }); - const answersUpdate = { - details: 'blah', - stats: { votes: 1, count: '3' }, - }; + const answersUpdate = { details: 'blah', stats: { votes: 1, count: '3' } }; const q = Post.updateOne( { 'answers._id': '507f1f77bcf86cd799439011' }, - { $set: { 'answers.$': answersUpdate } } - ); + { $set: { 'answers.$': answersUpdate } }); - assert.deepEqual(q.getUpdate().$set['answers.$'].stats, { - votes: 1, - count: 3, - }); + assert.deepEqual(q.getUpdate().$set['answers.$'].stats, + { votes: 1, count: 3 }); done(); }); - it('$geoWithin with single nested schemas (gh-4044)', function (done) { - const locationSchema = new Schema( - { - type: { type: String }, - coordinates: [], - }, - { _id: false } - ); + it('$geoWithin with single nested schemas (gh-4044)', function(done) { + const locationSchema = new Schema({ + type: { type: String }, + coordinates: [] + }, { _id: false }); const schema = new Schema({ title: String, - location: { type: locationSchema, required: true }, + location: { type: locationSchema, required: true } }); schema.index({ location: '2dsphere' }); @@ -1998,37 +1812,29 @@ describe('Query', function () { $geoWithin: { $geometry: { type: 'Polygon', - coordinates: [ - [ - [-1, 0], - [-1, 3], - [4, 3], - [4, 0], - [-1, 0], - ], - ], - }, - }, - }, + coordinates: [[[-1, 0], [-1, 3], [4, 3], [4, 0], [-1, 0]]] + } + } + } }; - Model.find(query, function (error) { + Model.find(query, function(error) { assert.ifError(error); done(); }); }); - it('setDefaultsOnInsert with empty update (gh-3825)', function (done) { + it('setDefaultsOnInsert with empty update (gh-3825)', function(done) { const schema = new mongoose.Schema({ test: { type: Number, default: 8472 }, - name: String, + name: String }); const MyModel = db.model('Test', schema); const opts = { upsert: true }; - MyModel.updateOne({}, {}, opts, function (error) { + MyModel.updateOne({}, {}, opts, function(error) { assert.ifError(error); - MyModel.findOne({}, function (error, doc) { + MyModel.findOne({}, function(error, doc) { assert.ifError(error); assert.ok(doc); assert.strictEqual(doc.test, 8472); @@ -2038,48 +1844,46 @@ describe('Query', function () { }); }); - it('custom query methods (gh-3714)', function (done) { + it('custom query methods (gh-3714)', function(done) { const schema = new mongoose.Schema({ - name: String, + name: String }); - schema.query.byName = function (name) { + schema.query.byName = function(name) { return this.find({ name: name }); }; const MyModel = db.model('Test', schema); - MyModel.create({ name: 'Val' }, function (error) { + MyModel.create({ name: 'Val' }, function(error) { assert.ifError(error); - MyModel.find() - .byName('Val') - .exec(function (error, docs) { - assert.ifError(error); - assert.equal(docs.length, 1); - assert.equal(docs[0].name, 'Val'); - done(); - }); + MyModel.find().byName('Val').exec(function(error, docs) { + assert.ifError(error); + assert.equal(docs.length, 1); + assert.equal(docs[0].name, 'Val'); + done(); + }); }); }); - it('string as input (gh-4378)', function (done) { + it('string as input (gh-4378)', function(done) { const schema = new mongoose.Schema({ - name: String, + name: String }); const MyModel = db.model('Test', schema); - MyModel.findOne('', function (error) { + MyModel.findOne('', function(error) { assert.ok(error); assert.equal(error.name, 'ObjectParameterError'); done(); }); }); - it('handles geoWithin with $center and mongoose object (gh-4419)', function (done) { + it('handles geoWithin with $center and mongoose object (gh-4419)', function(done) { const areaSchema = new Schema({ name: String, - circle: Array, + circle: Array }); const Area = db.model('Test', areaSchema); @@ -2089,38 +1893,38 @@ describe('Query', function () { type: { type: String, enum: ['Point'], - default: 'Point', + default: 'Point' }, - coordinates: { type: [Number] }, - }, + coordinates: { type: [Number] } + } }); placeSchema.index({ geometry: '2dsphere' }); const Place = db.model('Place', placeSchema); const tromso = new Area({ name: 'Tromso, Norway', - circle: [[18.89, 69.62], 10 / 3963.2], + circle: [[18.89, 69.62], 10 / 3963.2] }); - tromso.save(function (error) { + tromso.save(function(error) { assert.ifError(error); const airport = { name: 'Center', geometry: { type: 'Point', - coordinates: [18.895, 69.67], - }, + coordinates: [18.895, 69.67] + } }; - Place.create(airport, function (error) { + Place.create(airport, function(error) { assert.ifError(error); const q = { geometry: { $geoWithin: { - $centerSphere: tromso.circle, - }, - }, + $centerSphere: tromso.circle + } + } }; - Place.find(q).exec(function (error, docs) { + Place.find(q).exec(function(error, docs) { assert.ifError(error); assert.equal(docs.length, 1); assert.equal(docs[0].name, 'Center'); @@ -2130,9 +1934,9 @@ describe('Query', function () { }); }); - it('$not with objects (gh-4495)', function (done) { + it('$not with objects (gh-4495)', function(done) { const schema = new Schema({ - createdAt: Date, + createdAt: Date }); const M = db.model('Test', schema); @@ -2140,9 +1944,9 @@ describe('Query', function () { createdAt: { $not: { $gte: '2016/09/02 00:00:00', - $lte: '2016/09/02 23:59:59', - }, - }, + $lte: '2016/09/02 23:59:59' + } + } }); q._castConditions(); @@ -2151,13 +1955,13 @@ describe('Query', function () { done(); }); - it('geoIntersects with mongoose doc as coords (gh-4408)', function (done) { + it('geoIntersects with mongoose doc as coords (gh-4408)', function(done) { const lineStringSchema = new Schema({ name: String, geo: { type: { type: String, default: 'LineString' }, - coordinates: [[Number]], - }, + coordinates: [[Number]] + } }); const LineString = db.model('Test', lineStringSchema); @@ -2165,34 +1969,28 @@ describe('Query', function () { const ls = { name: 'test', geo: { - coordinates: [ - [14.59, 24.847], - [28.477, 15.961], - ], - }, + coordinates: [[14.59, 24.847], [28.477, 15.961]] + } }; const ls2 = { name: 'test2', geo: { - coordinates: [ - [27.528, 25.006], - [14.063, 15.591], - ], - }, + coordinates: [[27.528, 25.006], [14.063, 15.591]] + } }; - LineString.create(ls, ls2, function (error, ls1) { + LineString.create(ls, ls2, function(error, ls1) { assert.ifError(error); const query = { geo: { $geoIntersects: { $geometry: { type: 'LineString', - coordinates: ls1.geo.coordinates, - }, - }, - }, + coordinates: ls1.geo.coordinates + } + } + } }; - LineString.find(query, function (error, results) { + LineString.find(query, function(error, results) { assert.ifError(error); assert.equal(results.length, 2); done(); @@ -2200,22 +1998,23 @@ describe('Query', function () { }); }); - it('string with $not (gh-4592)', function (done) { + it('string with $not (gh-4592)', function(done) { const TestSchema = new Schema({ - test: String, + test: String }); const Test = db.model('Test', TestSchema); - Test.findOne({ test: { $not: /test/ } }, function (error) { + Test.findOne({ test: { $not: /test/ } }, function(error) { assert.ifError(error); done(); }); }); - it('does not cast undefined to null in mongoose (gh-6236)', async function () { + it('does not cast undefined to null in mongoose (gh-6236)', async function() { + const TestSchema = new Schema({ - test: String, + test: String }); const Test = db.model('Test', TestSchema); @@ -2230,49 +2029,46 @@ describe('Query', function () { assert.equal(res.length, 1); }); - it('runs query setters with _id field (gh-5351)', function (done) { + it('runs query setters with _id field (gh-5351)', function(done) { const testSchema = new Schema({ - val: { type: String }, + val: { type: String } }); const Test = db.model('Test', testSchema); - Test.create({ val: 'A string' }) - .then(function () { + Test.create({ val: 'A string' }). + then(function() { return Test.findOne({}); - }) - .then(function (doc) { - return Test.findOneAndUpdate( - { _id: doc._id }, - { - $set: { - val: 'another string', - }, - }, - { new: true } - ); - }) - .then(function (doc) { + }). + then(function(doc) { + return Test.findOneAndUpdate({ _id: doc._id }, { + $set: { + val: 'another string' + } + }, { new: true }); + }). + then(function(doc) { assert.ok(doc); assert.equal(doc.val, 'another string'); - }) - .then(done) - .catch(done); + }). + then(done). + catch(done); }); - it('runs setters if query field is an array (gh-6277)', async function () { + it('runs setters if query field is an array (gh-6277)', async function() { const setterCalled = []; const schema = new Schema({ strings: { type: [String], - set: (v) => { + set: v => { setterCalled.push(v); return v; - }, - }, + } + } }); const Model = db.model('Test', schema); + await Model.find({ strings: 'test' }); assert.equal(setterCalled.length, 0); @@ -2281,32 +2077,30 @@ describe('Query', function () { assert.deepEqual(setterCalled, [['test']]); }); - it('$exists under $not (gh-4933)', function (done) { + it('$exists under $not (gh-4933)', function(done) { const TestSchema = new Schema({ - test: String, + test: String }); const Test = db.model('Test', TestSchema); - Test.findOne({ test: { $not: { $exists: true } } }, function (error) { + Test.findOne({ test: { $not: { $exists: true } } }, function(error) { assert.ifError(error); done(); }); }); - it('geojson underneath array (gh-5467)', function (done) { + it('geojson underneath array (gh-5467)', function(done) { const storySchema = new Schema({ name: String, - gallery: [ - { - src: String, - location: { - type: { type: String, enum: ['Point'] }, - coordinates: { type: [Number], default: void 0 }, - }, - timestamp: Date, + gallery: [{ + src: String, + location: { + type: { type: String, enum: ['Point'] }, + coordinates: { type: [Number], default: void 0 } }, - ], + timestamp: Date + }] }); storySchema.index({ 'gallery.location': '2dsphere' }); @@ -2317,83 +2111,73 @@ describe('Query', function () { $near: { $geometry: { type: 'Point', - coordinates: [51.53377166666667, -0.1197471666666667], + coordinates: [51.53377166666667, -0.1197471666666667] }, - $maxDistance: 500, - }, - }, + $maxDistance: 500 + } + } }; - Story.once('index', function (error) { + Story.once('index', function(error) { assert.ifError(error); - Story.updateOne( - q, - { name: 'test' }, - { upsert: true }, - function (error) { - assert.ifError(error); - done(); - } - ); + Story.updateOne(q, { name: 'test' }, { upsert: true }, function(error) { + assert.ifError(error); + done(); + }); }); }); - it('slice respects schema projections (gh-5450)', function (done) { + it('slice respects schema projections (gh-5450)', function(done) { const gameSchema = Schema({ name: String, developer: { type: String, - select: false, + select: false }, - arr: [Number], + arr: [Number] }); const Game = db.model('Test', gameSchema); - Game.create( - { name: 'Mass Effect', developer: 'BioWare', arr: [1, 2, 3] }, - function (error) { + Game.create({ name: 'Mass Effect', developer: 'BioWare', arr: [1, 2, 3] }, function(error) { + assert.ifError(error); + Game.findOne({ name: 'Mass Effect' }).slice({ arr: 1 }).exec(function(error, doc) { assert.ifError(error); - Game.findOne({ name: 'Mass Effect' }) - .slice({ arr: 1 }) - .exec(function (error, doc) { - assert.ifError(error); - assert.equal(doc.name, 'Mass Effect'); - assert.deepEqual(doc.toObject().arr, [1]); - assert.ok(!doc.developer); - done(); - }); - } - ); + assert.equal(doc.name, 'Mass Effect'); + assert.deepEqual(doc.toObject().arr, [1]); + assert.ok(!doc.developer); + done(); + }); + }); }); - it('overwrites when passing an object when path already set to primitive (gh-6097)', function () { + it('overwrites when passing an object when path already set to primitive (gh-6097)', function() { const schema = new mongoose.Schema({ status: String }); const Model = db.model('Test', schema); - return Model.where({ status: 'approved' }).where({ - status: { $ne: 'delayed' }, - }); + return Model. + where({ status: 'approved' }). + where({ status: { $ne: 'delayed' } }); }); - it('$exists for arrays and embedded docs (gh-4937)', function (done) { + it('$exists for arrays and embedded docs (gh-4937)', function(done) { const subSchema = new Schema({ - name: String, + name: String }); const TestSchema = new Schema({ test: [String], - sub: subSchema, + sub: subSchema }); const Test = db.model('Test', TestSchema); const q = { test: { $exists: true }, sub: { $exists: false } }; - Test.findOne(q, function (error) { + Test.findOne(q, function(error) { assert.ifError(error); done(); }); }); - it('report error in pre hook (gh-5520)', function (done) { + it('report error in pre hook (gh-5520)', function(done) { const TestSchema = new Schema({ name: String }); const ops = [ @@ -2405,11 +2189,11 @@ describe('Query', function () { 'replaceOne', 'update', 'updateOne', - 'updateMany', + 'updateMany' ]; - ops.forEach(function (op) { - TestSchema.pre(op, function (next) { + ops.forEach(function(op) { + TestSchema.pre(op, function(next) { this.error(new Error(op + ' error')); next(); }); @@ -2419,25 +2203,24 @@ describe('Query', function () { let numOps = ops.length; - ops.forEach(function (op) { - TestModel.find({}) - .updateOne({ name: 'test' }) - [op](function (error) { - assert.ok(error); - assert.equal(error.message, op + ' error'); - --numOps || done(); - }); + ops.forEach(function(op) { + TestModel.find({}).updateOne({ name: 'test' })[op](function(error) { + assert.ok(error); + assert.equal(error.message, op + ' error'); + --numOps || done(); + }); }); }); - it('cast error with custom error (gh-5520)', function (done) { + it('cast error with custom error (gh-5520)', function(done) { const TestSchema = new Schema({ name: Number }); const TestModel = db.model('Test', TestSchema); - TestModel.find({ name: 'not a number' }) - .error(new Error('woops')) - .exec(function (error) { + TestModel. + find({ name: 'not a number' }). + error(new Error('woops')). + exec(function(error) { assert.ok(error); // CastError check happens **after** `.error()` assert.equal(error.name, 'CastError'); @@ -2445,15 +2228,15 @@ describe('Query', function () { }); }); - it('change deleteOne to updateOne for soft deletes using $isDeleted (gh-4428)', function (done) { + it('change deleteOne to updateOne for soft deletes using $isDeleted (gh-4428)', function(done) { const schema = new mongoose.Schema({ name: String, - isDeleted: Boolean, + isDeleted: Boolean }); - schema.pre('remove', function (next) { + schema.pre('remove', function(next) { const _this = this; - this.constructor.updateOne({ isDeleted: true }, function (error) { + this.constructor.updateOne({ isDeleted: true }, function(error) { // Force mongoose to consider this doc as deleted. _this.$isDeleted(true); next(error); @@ -2462,11 +2245,11 @@ describe('Query', function () { const M = db.model('Test', schema); - M.create({ name: 'test' }, function (error, doc) { + M.create({ name: 'test' }, function(error, doc) { assert.ifError(error); - doc.remove(function (error) { + doc.remove(function(error) { assert.ifError(error); - M.findById(doc._id, function (error, doc) { + M.findById(doc._id, function(error, doc) { assert.ifError(error); assert.ok(doc); assert.equal(doc.isDeleted, true); @@ -2476,29 +2259,26 @@ describe('Query', function () { }); }); - it('child schema with select: false in multiple paths (gh-5603)', function (done) { - const ChildSchema = new mongoose.Schema( - { - field: { - type: String, - select: false, - }, - _id: false, + it('child schema with select: false in multiple paths (gh-5603)', function(done) { + const ChildSchema = new mongoose.Schema({ + field: { + type: String, + select: false }, - { id: false } - ); + _id: false + }, { id: false }); const ParentSchema = new mongoose.Schema({ child: ChildSchema, - child2: ChildSchema, + child2: ChildSchema }); const Parent = db.model('Parent', ParentSchema); const ogParent = new Parent(); ogParent.child = { field: 'test' }; ogParent.child2 = { field: 'test' }; - ogParent.save(function (error) { + ogParent.save(function(error) { assert.ifError(error); - Parent.findById(ogParent._id).exec(function (error, doc) { + Parent.findById(ogParent._id).exec(function(error, doc) { assert.ifError(error); assert.ok(!doc.child.field); assert.ok(!doc.child2.field); @@ -2507,12 +2287,12 @@ describe('Query', function () { }); }); - it('errors in post init (gh-5592)', function (done) { + it('errors in post init (gh-5592)', function(done) { const TestSchema = new Schema(); let count = 0; - TestSchema.post('init', function () { - throw new Error('Failed! ' + count++); + TestSchema.post('init', function() { + throw new Error('Failed! ' + (count++)); }); const TestModel = db.model('Test', TestSchema); @@ -2522,9 +2302,9 @@ describe('Query', function () { docs.push({}); } - TestModel.create(docs, function (error) { + TestModel.create(docs, function(error) { assert.ifError(error); - TestModel.find({}, function (error) { + TestModel.find({}, function(error) { assert.ok(error); assert.equal(error.message, 'Failed! 0'); assert.equal(count, 10); @@ -2533,32 +2313,32 @@ describe('Query', function () { }); }); - it('with non-object args (gh-1698)', function (done) { + it('with non-object args (gh-1698)', function(done) { const schema = new mongoose.Schema({ - email: String, + email: String }); const M = db.model('Test', schema); - M.find(42, function (error) { + M.find(42, function(error) { assert.ok(error); assert.equal(error.name, 'ObjectParameterError'); done(); }); }); - describe('throw', function () { + describe('throw', function() { let listeners; - beforeEach(function () { + beforeEach(function() { listeners = process.listeners('uncaughtException'); process.removeAllListeners('uncaughtException'); }); - afterEach(function () { + afterEach(function() { process.on('uncaughtException', listeners[0]); }); - it('throw on sync exceptions in callbacks (gh-6178)', function (done) { + it('throw on sync exceptions in callbacks (gh-6178)', function(done) { // Deno doesn't support 'uncaughtException', so there's no way to test this in Deno // without starting a separate process. // See: https://stackoverflow.com/questions/64871554/deno-how-to-handle-exceptions @@ -2569,37 +2349,36 @@ describe('Query', function () { const schema = new Schema({}); const Test = db.model('Test', schema); - process.once('uncaughtException', (err) => { + process.once('uncaughtException', err => { assert.equal(err.message, 'Oops!'); done(); }); - Test.find({}, function () { - throw new Error('Oops!'); - }); + Test.find({}, function() { throw new Error('Oops!'); }); }); }); - it.skip('set overwrite after update() (gh-4740)', async function () { + it.skip('set overwrite after update() (gh-4740)', async function() { const schema = new Schema({ name: String, age: Number }); const User = db.model('User', schema); + await User.create({ name: 'Bar', age: 29 }); - await User.where({ name: 'Bar' }) - .update({ name: 'Baz' }) - .setOptions({ overwrite: true }); + await User.where({ name: 'Bar' }). + update({ name: 'Baz' }). + setOptions({ overwrite: true }); const doc = await User.findOne(); assert.equal(doc.name, 'Baz'); assert.ok(!doc.age); }); - it('queries with BSON overflow (gh-5812)', function (done) { + it('queries with BSON overflow (gh-5812)', function(done) { this.timeout(10000); const schema = new mongoose.Schema({ - email: String, + email: String }); const model = db.model('Test', schema); @@ -2609,22 +2388,20 @@ describe('Query', function () { bigData[i] = 'test1234567890'; } - model - .find({ email: { $in: bigData } }) - .lean() - .then(function () { + model.find({ email: { $in: bigData } }).lean(). + then(function() { done(new Error('Expected an error')); - }) - .catch(function (error) { + }). + catch(function(error) { assert.ok(error); assert.ok(error.message !== 'Expected error'); done(); }); }); - it('consistently return query when callback specified (gh-6271)', function (done) { + it('consistently return query when callback specified (gh-6271)', function(done) { const schema = new mongoose.Schema({ - n: Number, + n: Number }); const Model = db.model('Test', schema); @@ -2632,21 +2409,17 @@ describe('Query', function () { Model.create({ n: 0 }, (err, doc) => { assert.ifError(err); - const updateQuery = Model.findOneAndUpdate( - { _id: doc._id }, - { $inc: { n: 1 } }, - { new: true }, - (err, doc) => { - assert.ifError(err); - assert.equal(doc.n, 1); - done(); - } - ); + const updateQuery = Model.findOneAndUpdate({ _id: doc._id }, { $inc: { n: 1 } }, { new: true }, (err, doc) => { + assert.ifError(err); + assert.equal(doc.n, 1); + done(); + }); assert.ok(updateQuery instanceof Query); }); }); - it('explain() (gh-6625)', async function () { + it('explain() (gh-6625)', async function() { + const schema = new mongoose.Schema({ n: Number }); const Model = db.model('Test', schema); @@ -2663,36 +2436,25 @@ describe('Query', function () { assert.equal(res[0].n, 42); }); - it('cast embedded discriminators with dot notation (gh-6027)', async function () { - const ownerSchema = new Schema( - { - _id: false, - }, - { - discriminatorKey: 'type', - } - ); + it('cast embedded discriminators with dot notation (gh-6027)', async function() { - const userOwnerSchema = new Schema( - { - id: { type: Schema.Types.ObjectId, required: true }, - }, - { _id: false } - ); + const ownerSchema = new Schema({ + _id: false + }, { + discriminatorKey: 'type' + }); - const tagOwnerSchema = new Schema( - { - id: { type: String, required: true }, - }, - { _id: false } - ); + const userOwnerSchema = new Schema({ + id: { type: Schema.Types.ObjectId, required: true } + }, { _id: false }); - const activitySchema = new Schema( - { - owner: { type: ownerSchema, required: true }, - }, - { _id: false } - ); + const tagOwnerSchema = new Schema({ + id: { type: String, required: true } + }, { _id: false }); + + const activitySchema = new Schema({ + owner: { type: ownerSchema, required: true } + }, { _id: false }); activitySchema.path('owner').discriminator('user', userOwnerSchema); activitySchema.path('owner').discriminator('tag', tagOwnerSchema); @@ -2703,55 +2465,44 @@ describe('Query', function () { { owner: { id: '5a042f742a91c1db447534d5', - type: 'user', - }, + type: 'user' + } }, { owner: { id: 'asdf', - type: 'tag', - }, - }, + type: 'tag' + } + } ]); const activity = await Activity.findOne({ 'owner.type': 'user', - 'owner.id': '5a042f742a91c1db447534d5', + 'owner.id': '5a042f742a91c1db447534d5' }); assert.ok(activity); assert.equal(activity.owner.type, 'user'); }); - it('cast embedded discriminators with embedded obj (gh-6027)', async function () { - const ownerSchema = new Schema( - { - _id: false, - }, - { - discriminatorKey: 'type', - } - ); + it('cast embedded discriminators with embedded obj (gh-6027)', async function() { - const userOwnerSchema = new Schema( - { - id: { type: Schema.Types.ObjectId, required: true }, - }, - { _id: false } - ); + const ownerSchema = new Schema({ + _id: false + }, { + discriminatorKey: 'type' + }); - const tagOwnerSchema = new Schema( - { - id: { type: String, required: true }, - }, - { _id: false } - ); + const userOwnerSchema = new Schema({ + id: { type: Schema.Types.ObjectId, required: true } + }, { _id: false }); - const activitySchema = new Schema( - { - owner: { type: ownerSchema, required: true }, - }, - { _id: false } - ); + const tagOwnerSchema = new Schema({ + id: { type: String, required: true } + }, { _id: false }); + + const activitySchema = new Schema({ + owner: { type: ownerSchema, required: true } + }, { _id: false }); activitySchema.path('owner').discriminator('user', userOwnerSchema); activitySchema.path('owner').discriminator('tag', tagOwnerSchema); @@ -2762,44 +2513,36 @@ describe('Query', function () { { owner: { id: '5a042f742a91c1db447534d5', - type: 'user', - }, + type: 'user' + } }, { owner: { id: 'asdf', - type: 'tag', - }, - }, + type: 'tag' + } + } ]); const activity = await Activity.findOne({ owner: { type: 'user', - id: '5a042f742a91c1db447534d5', - }, + id: '5a042f742a91c1db447534d5' + } }); assert.ok(activity); assert.equal(activity.owner.type, 'user'); }); - it('cast embedded discriminators with $elemMatch discriminator key (gh-7449)', async function () { - const ListingLineSchema = new Schema( - { - sellerId: Number, - }, - { strictQuery: false } - ); + it('cast embedded discriminators with $elemMatch discriminator key (gh-7449)', async function() { + const ListingLineSchema = new Schema({ + sellerId: Number + }, { strictQuery: false }); const OrderSchema = new Schema({ - lines: [ - new Schema( - { - amount: Number, - }, - { discriminatorKey: 'kind', strictQuery: false } - ), - ], + lines: [new Schema({ + amount: Number + }, { discriminatorKey: 'kind', strictQuery: false })] }); OrderSchema.path('lines').discriminator('listing', ListingLineSchema); @@ -2809,27 +2552,27 @@ describe('Query', function () { await Order.create({ lines: { kind: 'listing', sellerId: 42 } }); let count = await Order.countDocuments({ - lines: { $elemMatch: { kind: 'listing', sellerId: '42' } }, + lines: { $elemMatch: { kind: 'listing', sellerId: '42' } } }); assert.strictEqual(count, 1); count = await Order.countDocuments({ - lines: { $elemMatch: { sellerId: '42' } }, + lines: { $elemMatch: { sellerId: '42' } } }); assert.strictEqual(count, 0); }); - it('handles geoWithin with mongoose docs (gh-4392)', async function () { + it('handles geoWithin with mongoose docs (gh-4392)', async function() { const areaSchema = new Schema({ name: { type: String }, loc: { type: { type: String, enum: ['Polygon'], - default: 'Polygon', + default: 'Polygon' }, - coordinates: [[[Number]]], - }, + coordinates: [[[Number]]] + } }); const Area = db.model('Test', areaSchema); @@ -2839,112 +2582,109 @@ describe('Query', function () { type: { type: String, enum: ['Point'], - default: 'Point', + default: 'Point' }, - coordinates: { type: [Number] }, + coordinates: { type: [Number] } }, properties: { - temperature: { type: Number }, - }, + temperature: { type: Number } + } }); observationSchema.index({ geometry: '2dsphere' }); const Observation = db.model('Test1', observationSchema); await Observation.init(); + const tromso = new Area({ name: 'Tromso, Norway', loc: { type: 'Polygon', - coordinates: [ - [ - [18.89, 69.62], - [18.89, 69.72], - [19.03, 69.72], - [19.03, 69.62], - [18.89, 69.62], - ], - ], - }, + coordinates: [[ + [18.89, 69.62], + [18.89, 69.72], + [19.03, 69.72], + [19.03, 69.62], + [18.89, 69.62] + ]] + } }); await tromso.save(); const observation = { geometry: { type: 'Point', - coordinates: [18.895, 69.67], - }, + coordinates: [18.895, 69.67] + } }; await Observation.create(observation); - const docs = await Observation.find() - .where('geometry') - .within() - .geometry(tromso.loc) - .exec(); + + const docs = await Observation. + find(). + where('geometry').within().geometry(tromso.loc). + exec(); assert.equal(docs.length, 1); }); }); - describe('handles falsy and object projections with defaults (gh-3256)', function () { + describe('handles falsy and object projections with defaults (gh-3256)', function() { let MyModel; - before(function () { + before(function() { const PersonSchema = new Schema({ name: String, lastName: String, dependents: [String], - salary: { type: Number, default: 25000 }, + salary: { type: Number, default: 25000 } }); db.deleteModel(/Person/); MyModel = db.model('Person', PersonSchema); }); - beforeEach(async function () { + beforeEach(async function() { await MyModel.collection.insertOne({ name: 'John', lastName: 'Doe', - dependents: ['Jake', 'Jill', 'Jane'], - }); - }); - - it('falsy projection', function (done) { - MyModel.findOne({ name: 'John' }, { lastName: false }).exec(function ( - error, - person - ) { - assert.ifError(error); - assert.equal(person.salary, 25000); - done(); + dependents: ['Jake', 'Jill', 'Jane'] }); }); - it('slice projection', function (done) { - MyModel.findOne({ name: 'John' }, { dependents: { $slice: 1 } }).exec( - function (error, person) { + it('falsy projection', function(done) { + MyModel.findOne({ name: 'John' }, { lastName: false }). + exec(function(error, person) { assert.ifError(error); assert.equal(person.salary, 25000); done(); - } - ); + }); }); - it('empty projection', function (done) { - MyModel.findOne({ name: 'John' }, {}).exec(function (error, person) { + it('slice projection', function(done) { + MyModel.findOne({ name: 'John' }, { dependents: { $slice: 1 } }).exec(function(error, person) { assert.ifError(error); assert.equal(person.salary, 25000); done(); }); }); + + it('empty projection', function(done) { + MyModel.findOne({ name: 'John' }, {}). + exec(function(error, person) { + assert.ifError(error); + assert.equal(person.salary, 25000); + done(); + }); + }); }); - describe('count', function () { - it('calls utils.toObject on conditions (gh-6323)', async function () { + describe('count', function() { + it('calls utils.toObject on conditions (gh-6323)', async function() { + const priceSchema = new Schema({ key: String, - price: Number, + price: Number }); const Model = db.model('Test', priceSchema); @@ -2971,8 +2711,8 @@ describe('Query', function () { }); }); - describe('setQuery', function () { - it('replaces existing query with new value (gh-6854)', function () { + describe('setQuery', function() { + it('replaces existing query with new value (gh-6854)', function() { const q = new Query({}); q.where('userName').exists(); q.setQuery({ a: 1 }); @@ -2980,12 +2720,13 @@ describe('Query', function () { }); }); - it('map (gh-7142)', async function () { + it('map (gh-7142)', async function() { const Model = db.model('Test', new Schema({ name: String })); + await Model.create({ name: 'test' }); const now = new Date(); - const res = await Model.findOne().transform((res) => { + const res = await Model.findOne().transform(res => { res.loadedAt = now; return res; }); @@ -2993,19 +2734,20 @@ describe('Query', function () { assert.equal(res.loadedAt, now); }); - describe('orFail (gh-6841)', function () { + describe('orFail (gh-6841)', function() { let Model; - before(function () { + before(function() { db.deleteModel(/Test/); Model = db.model('Test', new Schema({ name: String })); }); - beforeEach(function () { + beforeEach(function() { return Model.deleteMany({}).then(() => Model.create({ name: 'Test' })); }); - it('find()', async function () { + it('find()', async function() { + let threw = false; try { await Model.find({ name: 'na' }).orFail(() => new Error('Oops!')); @@ -3021,7 +2763,8 @@ describe('Query', function () { assert.equal(res[0].name, 'Test'); }); - it('findOne()', async function () { + it('findOne()', async function() { + let threw = false; try { await Model.findOne({ name: 'na' }).orFail(() => new Error('Oops!')); @@ -3033,13 +2776,12 @@ describe('Query', function () { assert.ok(threw); // Shouldn't throw - const res = await Model.findOne({ name: 'Test' }).orFail( - new Error('Oops') - ); + const res = await Model.findOne({ name: 'Test' }).orFail(new Error('Oops')); assert.equal(res.name, 'Test'); }); - it('deleteMany()', async function () { + it('deleteMany()', async function() { + let threw = false; try { await Model.deleteMany({ name: 'na' }).orFail(new Error('Oops!')); @@ -3051,13 +2793,12 @@ describe('Query', function () { assert.ok(threw); // Shouldn't throw - const res = await Model.deleteMany({ name: 'Test' }).orFail( - new Error('Oops') - ); + const res = await Model.deleteMany({ name: 'Test' }).orFail(new Error('Oops')); assert.equal(res.deletedCount, 1); }); - it('deleteOne()', async function () { + it('deleteOne()', async function() { + let threw = false; try { await Model.deleteOne({ name: 'na' }).orFail(new Error('Oops!')); @@ -3069,13 +2810,12 @@ describe('Query', function () { assert.ok(threw); // Shouldn't throw - const res = await Model.deleteOne({ name: 'Test' }).orFail( - new Error('Oops') - ); + const res = await Model.deleteOne({ name: 'Test' }).orFail(new Error('Oops')); assert.equal(res.deletedCount, 1); }); - it('remove()', async function () { + it('remove()', async function() { + let threw = false; try { await Model.remove({ name: 'na' }).orFail(new Error('Oops!')); @@ -3087,18 +2827,14 @@ describe('Query', function () { assert.ok(threw); // Shouldn't throw - const res = await Model.remove({ name: 'Test' }).orFail( - new Error('Oops') - ); + const res = await Model.remove({ name: 'Test' }).orFail(new Error('Oops')); assert.equal(res.deletedCount, 1); }); - it('replaceOne()', async function () { + it('replaceOne()', async function() { let threw = false; try { - await Model.replaceOne({ name: 'na' }, { name: 'bar' }).orFail( - new Error('Oops!') - ); + await Model.replaceOne({ name: 'na' }, { name: 'bar' }).orFail(new Error('Oops!')); } catch (error) { assert.ok(error); assert.equal(error.message, 'Oops!'); @@ -3107,19 +2843,16 @@ describe('Query', function () { assert.ok(threw); // Shouldn't throw - const res = await Model.replaceOne( - { name: 'Test' }, - { name: 'bar' } - ).orFail(new Error('Oops')); + const res = await Model.replaceOne({ name: 'Test' }, { name: 'bar' }).orFail(new Error('Oops')); assert.equal(res.modifiedCount, 1); }); - it('update()', async function () { + it('update()', async function() { + let threw = false; try { - await Model.update({ name: 'na' }, { name: 'foo' }).orFail( - new Error('Oops!') - ); + await Model.update({ name: 'na' }, { name: 'foo' }). + orFail(new Error('Oops!')); } catch (error) { assert.ok(error); assert.equal(error.message, 'Oops!'); @@ -3128,18 +2861,16 @@ describe('Query', function () { assert.ok(threw); // Shouldn't throw - const res = await Model.update({}, { name: 'Test2' }).orFail( - new Error('Oops') - ); + const res = await Model.update({}, { name: 'Test2' }).orFail(new Error('Oops')); assert.equal(res.modifiedCount, 1); }); - it('updateMany()', async function () { + it('updateMany()', async function() { + let threw = false; try { - await Model.updateMany({ name: 'na' }, { name: 'foo' }).orFail( - new Error('Oops!') - ); + await Model.updateMany({ name: 'na' }, { name: 'foo' }). + orFail(new Error('Oops!')); } catch (error) { assert.ok(error); assert.equal(error.message, 'Oops!'); @@ -3148,18 +2879,16 @@ describe('Query', function () { assert.ok(threw); // Shouldn't throw - const res = await Model.updateMany({}, { name: 'Test2' }).orFail( - new Error('Oops') - ); + const res = await Model.updateMany({}, { name: 'Test2' }).orFail(new Error('Oops')); assert.equal(res.modifiedCount, 1); }); - it('updateOne()', async function () { + it('updateOne()', async function() { + let threw = false; try { - await Model.updateOne({ name: 'na' }, { name: 'foo' }).orFail( - new Error('Oops!') - ); + await Model.updateOne({ name: 'na' }, { name: 'foo' }). + orFail(new Error('Oops!')); } catch (error) { assert.ok(error); assert.equal(error.message, 'Oops!'); @@ -3168,18 +2897,16 @@ describe('Query', function () { assert.ok(threw); // Shouldn't throw - const res = await Model.updateOne({}, { name: 'Test2' }).orFail( - new Error('Oops') - ); + const res = await Model.updateOne({}, { name: 'Test2' }).orFail(new Error('Oops')); assert.equal(res.modifiedCount, 1); }); - it('findOneAndUpdate()', async function () { + it('findOneAndUpdate()', async function() { + let threw = false; try { - await Model.findOneAndUpdate({ name: 'na' }, { name: 'foo' }).orFail( - new Error('Oops!') - ); + await Model.findOneAndUpdate({ name: 'na' }, { name: 'foo' }). + orFail(new Error('Oops!')); } catch (error) { assert.ok(error); assert.equal(error.message, 'Oops!'); @@ -3188,16 +2915,16 @@ describe('Query', function () { assert.ok(threw); // Shouldn't throw - const res = await Model.findOneAndUpdate({}, { name: 'Test2' }).orFail( - new Error('Oops') - ); + const res = await Model.findOneAndUpdate({}, { name: 'Test2' }).orFail(new Error('Oops')); assert.equal(res.name, 'Test'); }); - it('findOneAndDelete()', async function () { + it('findOneAndDelete()', async function() { + let threw = false; try { - await Model.findOneAndDelete({ name: 'na' }).orFail(new Error('Oops!')); + await Model.findOneAndDelete({ name: 'na' }). + orFail(new Error('Oops!')); } catch (error) { assert.ok(error); assert.equal(error.message, 'Oops!'); @@ -3206,16 +2933,15 @@ describe('Query', function () { assert.ok(threw); // Shouldn't throw - const res = await Model.findOneAndDelete({ name: 'Test' }).orFail( - new Error('Oops') - ); + const res = await Model.findOneAndDelete({ name: 'Test' }).orFail(new Error('Oops')); assert.equal(res.name, 'Test'); }); - it('executes before post hooks (gh-7280)', async function () { + it('executes before post hooks (gh-7280)', async function() { + const schema = new Schema({ name: String }); const docs = []; - schema.post('findOne', function (doc, next) { + schema.post('findOne', function(doc, next) { docs.push(doc); next(); }); @@ -3235,20 +2961,16 @@ describe('Query', function () { assert.equal(docs.length, 0); // Shouldn't throw - const res = await Model.findOne({ name: 'Test' }).orFail( - new Error('Oops') - ); + const res = await Model.findOne({ name: 'Test' }).orFail(new Error('Oops')); assert.equal(res.name, 'Test'); assert.equal(docs.length, 1); }); - it('throws DocumentNotFoundError by default execute (gh-7409)', async function () { - const err = await Model.findOne({ name: 'na' }) - .orFail() - .then( - () => null, - (err) => err - ); + it('throws DocumentNotFoundError by default execute (gh-7409)', async function() { + + const err = await Model.findOne({ name: 'na' }). + orFail(). + then(() => null, err => err); assert.equal(err.name, 'DocumentNotFoundError', err.stack); assert.ok(err.message.indexOf('na') !== -1, err.message); assert.ok(err.message.indexOf('"Test"') !== -1, err.message); @@ -3256,27 +2978,28 @@ describe('Query', function () { }); }); - describe('getPopulatedPaths', function () { - it("doesn't break on a query without population (gh-6677)", async function () { + describe('getPopulatedPaths', function() { + it('doesn\'t break on a query without population (gh-6677)', async function() { const schema = new Schema({ name: String }); - schema.pre('findOne', function () { + schema.pre('findOne', function() { assert.deepStrictEqual(this.getPopulatedPaths(), []); }); const Model = db.model('Test', schema); + await Model.findOne({}); }); - it('returns an array of populated paths as strings (gh-6677)', async function () { + it('returns an array of populated paths as strings (gh-6677)', async function() { const otherSchema = new Schema({ name: String }); const schema = new Schema({ other: { type: Schema.Types.ObjectId, - ref: 'Test1', - }, + ref: 'Test1' + } }); - schema.pre('findOne', function () { + schema.pre('findOne', function() { assert.deepStrictEqual(this.getPopulatedPaths(), ['other']); }); @@ -3286,39 +3009,35 @@ describe('Query', function () { const other = new Other({ name: 'one' }); const test = new Test({ other: other._id }); + await other.save(); await test.save(); await Test.findOne({}).populate('other'); }); - it('returns deep populated paths (gh-7757)', function () { + it('returns deep populated paths (gh-7757)', function() { db.model('Test3', new Schema({ name: String })); db.model('Test2', new Schema({ level3: { type: String, ref: 'Test3' } })); - const L1 = db.model( - 'Test', - new Schema({ level1: { type: String, ref: 'Test2' } }) - ); + const L1 = db.model('Test', + new Schema({ level1: { type: String, ref: 'Test2' } })); const query = L1.find().populate({ path: 'level1', populate: { path: 'level2', populate: { - path: 'level3', - }, - }, + path: 'level3' + } + } }); - assert.deepEqual(query.getPopulatedPaths(), [ - 'level1', - 'level1.level2', - 'level1.level2.level3', - ]); + assert.deepEqual(query.getPopulatedPaths(), + ['level1', 'level1.level2', 'level1.level2.level3']); }); }); - describe('setUpdate', function () { - it('replaces existing update doc with new value', function () { + describe('setUpdate', function() { + it('replaces existing update doc with new value', function() { const q = new Query({}); q.set('testing', '123'); q.setUpdate({ $set: { newPath: 'newValue' } }); @@ -3327,53 +3046,49 @@ describe('Query', function () { }); }); - describe('get() (gh-7312)', function () { - it('works with using $set', function () { + describe('get() (gh-7312)', function() { + it('works with using $set', function() { const q = new Query({}); q.updateOne({}, { $set: { name: 'Jean-Luc Picard' } }); assert.equal(q.get('name'), 'Jean-Luc Picard'); }); - it('works with $set syntactic sugar', function () { + it('works with $set syntactic sugar', function() { const q = new Query({}); q.updateOne({}, { name: 'Jean-Luc Picard' }); assert.equal(q.get('name'), 'Jean-Luc Picard'); }); - it('works with mixed', function () { + it('works with mixed', function() { const q = new Query({}); q.updateOne({}, { name: 'Jean-Luc Picard', $set: { age: 59 } }); assert.equal(q.get('name'), 'Jean-Luc Picard'); }); - it('$set overwrites existing', function () { + it('$set overwrites existing', function() { const M = db.model('Test', new Schema({ name: String })); - const q = M.updateOne( - {}, - { - name: 'Jean-Luc Picard', - $set: { name: 'William Riker' }, - }, - { upsert: true } - ); + const q = M.updateOne({}, { + name: 'Jean-Luc Picard', + $set: { name: 'William Riker' } + }, { upsert: true }); assert.equal(q.get('name'), 'Jean-Luc Picard'); - return q - .exec() - .then(() => M.findOne()) - .then((doc) => assert.equal(doc.name, 'Jean-Luc Picard')); + return q.exec(). + then(() => M.findOne()). + then(doc => assert.equal(doc.name, 'Jean-Luc Picard')); }); }); - it('allows skipping timestamps in updateOne() (gh-6980)', async function () { + it('allows skipping timestamps in updateOne() (gh-6980)', async function() { const schema = new Schema({ name: String }, { timestamps: true }); const M = db.model('Test', schema); + const doc = await M.create({ name: 'foo' }); assert.ok(doc.createdAt); assert.ok(doc.updatedAt); @@ -3385,29 +3100,22 @@ describe('Query', function () { const res = await M.findOneAndUpdate({}, { name: 'bar' }, opts); assert.equal(res.name, 'bar'); - assert.ok( - res.updatedAt.valueOf() <= start, - `Expected ${res.updatedAt.valueOf()} <= ${start}` - ); + assert.ok(res.updatedAt.valueOf() <= start, + `Expected ${res.updatedAt.valueOf()} <= ${start}`); }); - it('increments timestamps for nested subdocs (gh-4412)', async function () { - const childSchema = new Schema( - { name: String }, - { - timestamps: true, - versionKey: false, - } - ); - const parentSchema = new Schema( - { child: childSchema }, - { - // timestamps: true, - versionKey: false, - } - ); + it('increments timestamps for nested subdocs (gh-4412)', async function() { + const childSchema = new Schema({ name: String }, { + timestamps: true, + versionKey: false + }); + const parentSchema = new Schema({ child: childSchema }, { + // timestamps: true, + versionKey: false + }); const Parent = db.model('Parent', parentSchema); + let doc = await Parent.create({ child: { name: 'foo' } }); assert.ok(doc.child.updatedAt); assert.ok(doc.child.createdAt); @@ -3438,30 +3146,22 @@ describe('Query', function () { assert.ok(updatedAt > start, `Expected ${updatedAt} > ${start}`); }); - describe('increments timestamps for arrays of nested subdocs (gh-4412)', function () { + describe('increments timestamps for arrays of nested subdocs (gh-4412)', function() { let Parent; - before(function () { - const childSchema = new Schema( - { name: String }, - { - timestamps: true, - versionKey: false, - } - ); - const parentSchema = new Schema( - { children: [childSchema] }, - { - versionKey: false, - } - ); + before(function() { + const childSchema = new Schema({ name: String }, { + timestamps: true, + versionKey: false + }); + const parentSchema = new Schema({ children: [childSchema] }, { + versionKey: false }); Parent = db.model('Parent', parentSchema); }); - it('$set nested property with numeric position', async function () { - const kids = 'foo bar baz'.split(' ').map((n) => { - return { name: `${n}` }; - }); + it('$set nested property with numeric position', async function() { + + const kids = 'foo bar baz'.split(' ').map(n => { return { name: `${n}` };}); const doc = await Parent.create({ children: kids }); assert.ok(doc.children[0].updatedAt && doc.children[0].createdAt); assert.ok(doc.children[1].updatedAt && doc.children[1].createdAt); @@ -3478,16 +3178,13 @@ describe('Query', function () { const updatedAt = found.children[0].updatedAt; const name = found.children[0].name; assert.ok(name, 'Luke'); - assert.ok( - updatedAt.valueOf() > start.valueOf(), - `Expected ${updatedAt} > ${start}` - ); + assert.ok(updatedAt.valueOf() > start.valueOf(), + `Expected ${updatedAt} > ${start}`); }); - it('$set numeric element', async function () { - const kids = 'foo bar baz'.split(' ').map((n) => { - return { name: `${n}` }; - }); + it('$set numeric element', async function() { + + const kids = 'foo bar baz'.split(' ').map(n => { return { name: `${n}` };}); const doc = await Parent.create({ children: kids }); assert.ok(doc.children[0].updatedAt && doc.children[0].createdAt); assert.ok(doc.children[1].updatedAt && doc.children[1].createdAt); @@ -3507,10 +3204,9 @@ describe('Query', function () { assert.ok(updatedAt > start, `Expected ${updatedAt} > ${start}`); }); - it('$set with positional operator', async function () { - const kids = 'foo bar baz'.split(' ').map((n) => { - return { name: `${n}` }; - }); + it('$set with positional operator', async function() { + + const kids = 'foo bar baz'.split(' ').map(n => { return { name: `${n}` };}); const doc = await Parent.create({ children: kids }); assert.ok(doc.children[0].updatedAt && doc.children[0].createdAt); assert.ok(doc.children[1].updatedAt && doc.children[1].createdAt); @@ -3530,15 +3226,13 @@ describe('Query', function () { assert.ok(updatedAt > start, `Expected ${updatedAt} > ${start}`); }); - it('$set with positional operator and array (gh-7106)', async function () { + it('$set with positional operator and array (gh-7106)', async function() { + const subSub = new Schema({ x: String }); const sub = new Schema({ name: String, subArr: [subSub] }); - const schema = new Schema( - { arr: [sub] }, - { - timestamps: true, - } - ); + const schema = new Schema({ arr: [sub] }, { + timestamps: true + }); const Test = db.model('Test', schema); @@ -3546,12 +3240,10 @@ describe('Query', function () { const set = { $set: { 'arr.$.subArr': [{ x: 'b' }] } }; await Test.create({ - arr: [ - { - name: 'abc', - subArr: [{ x: 'a' }], - }, - ], + arr: [{ + name: 'abc', + subArr: [{ x: 'a' }] + }] }); await Test.updateOne(cond, set); @@ -3562,22 +3254,16 @@ describe('Query', function () { }); }); - it('strictQuery option (gh-4136) (gh-7178)', async function () { - const modelSchema = new Schema( - { - field: Number, - nested: { path: String }, - }, - { strictQuery: 'throw' } - ); + it('strictQuery option (gh-4136) (gh-7178)', async function() { + const modelSchema = new Schema({ + field: Number, + nested: { path: String } + }, { strictQuery: 'throw' }); const Model = db.model('Test', modelSchema); // `find()` on a top-level path not in the schema - let err = await Model.find({ notInschema: 1 }).then( - () => null, - (e) => e - ); + let err = await Model.find({ notInschema: 1 }).then(() => null, e => e); assert.ok(err); assert.ok(err.message.indexOf('strictQuery') !== -1, err.message); @@ -3587,35 +3273,26 @@ describe('Query', function () { assert.ok(doc); // `find()` on a nested path not in the schema - err = await Model.find({ 'nested.bad': 'foo' }).then( - () => null, - (e) => e - ); + err = await Model.find({ 'nested.bad': 'foo' }).then(() => null, e => e); assert.ok(err); assert.ok(err.message.indexOf('strictQuery') !== -1, err.message); }); - it('strictQuery inherits from strict (gh-10763) (gh-4136) (gh-7178)', async function () { - const modelSchema = new Schema( - { - field: Number, - nested: { path: String }, - }, - { strict: 'throw' } - ); + it('strictQuery inherits from strict (gh-10763) (gh-4136) (gh-7178)', async function() { + const modelSchema = new Schema({ + field: Number, + nested: { path: String } + }, { strict: 'throw' }); const Model = db.model('Test', modelSchema); // `find()` on a top-level path not in the schema - const err = await Model.find({ notInschema: 1 }).then( - () => null, - (e) => e - ); + const err = await Model.find({ notInschema: 1 }).then(() => null, e => e); assert.ok(err); assert.ok(err.message.indexOf('strictQuery') !== -1, err.message); }); - it('strictQuery = true (gh-6032)', async function () { + it('strictQuery = true (gh-6032)', async function() { const modelSchema = new Schema({ field: Number }, { strictQuery: true }); const Model = db.model('Test', modelSchema); @@ -3627,12 +3304,13 @@ describe('Query', function () { assert.equal(docs.length, 1); }); - it('function defaults run after query result is inited (gh-7182)', async function () { + it('function defaults run after query result is inited (gh-7182)', async function() { const schema = new Schema({ kind: String, hasDefault: String }); - schema.path('hasDefault').default(function () { + schema.path('hasDefault').default(function() { return this.kind === 'test' ? 'success' : 'fail'; }); + const Model = db.model('Test', schema); await Model.create({ kind: 'test' }); @@ -3642,79 +3320,72 @@ describe('Query', function () { assert.equal(doc.hasDefault, 'success'); }); - it('merging objectids with where() (gh-7360)', function () { + it('merging objectids with where() (gh-7360)', function() { const Test = db.model('Test', new Schema({})); - return Test.create({}) - .then((doc) => - Test.find({ _id: doc._id.toString() }).where({ _id: doc._id }) - ) - .then((res) => assert.equal(res.length, 1)); + return Test.create({}). + then(doc => Test.find({ _id: doc._id.toString() }).where({ _id: doc._id })). + then(res => assert.equal(res.length, 1)); }); - it('maxTimeMS() (gh-7254)', async function () { + it('maxTimeMS() (gh-7254)', async function() { const Model = db.model('Test', new Schema({})); + await Model.create({}); - const res = await Model.find({ $where: 'sleep(1000) || true' }) - .maxTimeMS(10) - .then( - () => null, - (err) => err - ); + const res = await Model.find({ $where: 'sleep(1000) || true' }). + maxTimeMS(10). + then(() => null, err => err); assert.ok(res); assert.ok(res.message.indexOf('time limit') !== -1, res.message); }); - it('connection-level maxTimeMS() (gh-4066)', async function () { + it('connection-level maxTimeMS() (gh-4066)', async function() { db.options = db.options || {}; db.options.maxTimeMS = 10; const Model = db.model('Test', new Schema({})); + await Model.create({}); - const res = await Model.find({ $where: 'sleep(250) || true' }).then( - () => null, - (err) => err - ); + const res = await Model.find({ $where: 'sleep(250) || true' }). + then(() => null, err => err); assert.ok(res); assert.ok(res.message.indexOf('time limit') !== -1, res.message); delete db.options.maxTimeMS; }); - it('mongoose-level maxTimeMS() (gh-4066)', async function () { + it('mongoose-level maxTimeMS() (gh-4066)', async function() { db.base.options = db.base.options || {}; db.base.options.maxTimeMS = 10; const Model = db.model('Test', new Schema({})); + await Model.create({}); - const res = await Model.find({ $where: 'sleep(250) || true' }).then( - () => null, - (err) => err - ); + const res = await Model.find({ $where: 'sleep(250) || true' }). + then(() => null, err => err); assert.ok(res); assert.ok(res.message.indexOf('time limit') !== -1, res.message); delete db.base.options.maxTimeMS; }); - it('throws error with updateOne() and overwrite (gh-7475)', function () { + it('throws error with updateOne() and overwrite (gh-7475)', function() { const Model = db.model('Test', Schema({ name: String })); return Model.updateOne({}, { name: 'bar' }, { overwrite: true }).then( - () => { - throw new Error('Should have failed'); - }, - (err) => assert.ok(err.message.indexOf('updateOne') !== -1) + () => { throw new Error('Should have failed'); }, + err => assert.ok(err.message.indexOf('updateOne') !== -1) ); }); - it('sets deletedCount on result of remove() (gh-7629)', async function () { + it('sets deletedCount on result of remove() (gh-7629)', async function() { const schema = new Schema({ name: String }); const Model = db.model('Test', schema); + await Model.create({ name: 'foo' }); let res = await Model.remove({}); @@ -3724,21 +3395,22 @@ describe('Query', function () { assert.strictEqual(res.deletedCount, 0); }); - describe('merge()', function () { - it('copies populate() (gh-1790)', async function () { + describe('merge()', function() { + it('copies populate() (gh-1790)', async function() { const Car = db.model('Car', { color: String, model: String, owner: { type: Schema.Types.ObjectId, - ref: 'Person', - }, + ref: 'Person' + } }); const Person = db.model('Person', { - name: String, + name: String }); + const val = await Person.create({ name: 'Val' }); await Car.create({ color: 'Brown', model: 'Subaru', owner: val._id }); @@ -3750,22 +3422,22 @@ describe('Query', function () { }); }); - describe('Query#validate() (gh-7984)', function () { - it('middleware', function () { + describe('Query#validate() (gh-7984)', function() { + it('middleware', function() { const schema = new Schema({ password: { type: String, - validate: (v) => v.length >= 6, - required: true, - }, + validate: v => v.length >= 6, + required: true + } }); let docCalls = 0; - schema.post('validate', function () { + schema.post('validate', function() { ++docCalls; }); let queryCalls = 0; - schema.post('validate', { query: true }, function () { + schema.post('validate', { query: true }, function() { ++queryCalls; const pw = this.get('password'); assert.equal(pw, '6chars'); @@ -3775,37 +3447,34 @@ describe('Query', function () { const M = db.model('Test', schema); const opts = { runValidators: true, upsert: true, new: true }; - return M.findOneAndUpdate({}, { password: '6chars' }, opts).then( - (doc) => { - assert.equal(docCalls, 0); - assert.equal(queryCalls, 1); - assert.equal(doc.password, 'encryptedpassword'); - } - ); + return M.findOneAndUpdate({}, { password: '6chars' }, opts).then(doc => { + assert.equal(docCalls, 0); + assert.equal(queryCalls, 1); + assert.equal(doc.password, 'encryptedpassword'); + }); }); - it('pre("validate") errors (gh-7187)', async function () { + it('pre("validate") errors (gh-7187)', async function() { const addressSchema = Schema({ countryId: String }); - addressSchema.pre('validate', { query: true }, function () { + addressSchema.pre('validate', { query: true }, function() { throw new Error('Oops!'); }); const contactSchema = Schema({ addresses: [addressSchema] }); const Contact = db.model('Test', contactSchema); const update = { addresses: [{ countryId: 'foo' }] }; - const err = await Contact.updateOne({}, update, { - runValidators: true, - }).then( - () => null, - (err) => err - ); + const err = await Contact.updateOne( + {}, + update, + { runValidators: true } + ).then(() => null, err => err); assert.ok(err.errors['addresses.0']); assert.equal(err.errors['addresses.0'].message, 'Oops!'); }); }); - it('query with top-level _bsontype (gh-8222) (gh-8268)', async function () { + it('query with top-level _bsontype (gh-8222) (gh-8268)', async function() { const userSchema = Schema({ token: String }, { strictQuery: true }); const User = db.model('Test', userSchema); @@ -3819,80 +3488,67 @@ describe('Query', function () { assert.equal(doc.token, 'rightToken'); }); - it('casts $elemMatch with dbrefs (gh-8577)', async function () { + it('casts $elemMatch with dbrefs (gh-8577)', async function() { const ChatSchema = new Schema({ - members: [ - { - $ref: String, - $id: mongoose.ObjectId, - $db: String, - }, - ], + members: [{ + $ref: String, + $id: mongoose.ObjectId, + $db: String + }] }); const Chat = db.model('Test', ChatSchema); + const doc = await Chat.create({ - members: [ - { $ref: 'foo', $id: new mongoose.Types.ObjectId(), $db: 'foo' }, - ], + members: [{ $ref: 'foo', $id: new mongoose.Types.ObjectId(), $db: 'foo' }] }); const res = await Chat.findOne({ - members: { $elemMatch: { $id: doc.members[0].$id } }, + members: { $elemMatch: { $id: doc.members[0].$id } } }); assert.ok(res); }); - it('throws an error if executed multiple times (gh-7398)', async function () { + it('throws an error if executed multiple times (gh-7398)', async function() { const Test = db.model('Test', Schema({ name: String })); + const q = Test.findOne(); await q; - let err = await q.then( - () => null, - (err) => err - ); + let err = await q.then(() => null, err => err); assert.ok(err); assert.equal(err.name, 'MongooseError'); assert.equal(err.message, 'Query was already executed: Test.findOne({})'); assert.ok(err.originalStack); const cb = () => {}; - err = await Test.find(cb).then( - () => null, - (err) => err - ); + err = await Test.find(cb).then(() => null, err => err); assert.ok(err); assert.equal(err.name, 'MongooseError'); assert.equal(err.message, 'Query was already executed: Test.find({})'); assert.ok(err.originalStack); - err = await q.clone().then( - () => null, - (err) => err - ); + err = await q.clone().then(() => null, err => err); assert.ifError(err); }); - describe('stack traces', function () { - it('includes calling file for filter cast errors (gh-8691)', async function () { + describe('stack traces', function() { + it('includes calling file for filter cast errors (gh-8691)', async function() { const toCheck = ['find', 'findOne', 'deleteOne']; const Model = db.model('Test', Schema({})); + for (const fn of toCheck) { - const err = await Model[fn]({ _id: 'fail' }).then( - () => null, - (err) => err - ); + const err = await Model[fn]({ _id: 'fail' }).then(() => null, err => err); assert.ok(err); assert.ok(err.stack.includes(__filename), err.stack); } }); }); - it('setter priorVal (gh-8629)', function () { + it('setter priorVal (gh-8629)', function() { const priorVals = []; const schema = Schema({ name: { @@ -3900,30 +3556,29 @@ describe('Query', function () { set: (v, priorVal) => { priorVals.push(priorVal); return v; - }, - }, + } + } }); const Model = db.model('Test', schema); - return Model.updateOne({}, { name: 'bar' }) - .exec() - .then(() => assert.deepEqual(priorVals, [null])); + return Model.updateOne({}, { name: 'bar' }).exec(). + then(() => assert.deepEqual(priorVals, [null])); }); - describe('clone', function () { + describe('clone', function() { let Model; - beforeEach(function () { + beforeEach(function() { const schema = new Schema({ name: String, age: Number }); Model = db.model('Test', schema); return Model.create([ { name: 'Jean-Luc Picard', age: 59 }, - { name: 'Will Riker', age: 29 }, + { name: 'Will Riker', age: 29 } ]); }); - it('with findOne', async function () { + it('with findOne', async function() { const q = Model.findOne({ age: 29 }); const q2 = q.clone(); @@ -3940,7 +3595,7 @@ describe('Query', function () { assert.equal(doc.name, 'Will Riker'); }); - it('with deleteOne', async function () { + it('with deleteOne', async function() { const q = Model.deleteOne({ age: 29 }); await q; @@ -3953,11 +3608,8 @@ describe('Query', function () { assert.equal(await Model.findOne({ name: 'Will Riker' }), null); }); - it('with updateOne', async function () { - const q = Model.updateOne( - { name: 'Will Riker' }, - { name: 'Thomas Riker' } - ); + it('with updateOne', async function() { + const q = Model.updateOne({ name: 'Will Riker' }, { name: 'Thomas Riker' }); await q; assert.equal(await Model.findOne({ name: 'Will Riker' }), null); @@ -3970,7 +3622,7 @@ describe('Query', function () { assert.equal(await Model.findOne({ name: 'Will Riker' }), null); }); - it('with distinct', async function () { + it('with distinct', async function() { const q = Model.distinct('name'); const res = await q; @@ -3982,7 +3634,7 @@ describe('Query', function () { assert.deepEqual(res.sort(), ['Jean-Luc Picard', 'Will Riker']); }); - it('with hooks (gh-12365)', async function () { + it('with hooks (gh-12365)', async function() { db.deleteModel('Test'); const schema = new Schema({ name: String, age: Number }); @@ -3995,24 +3647,16 @@ describe('Query', function () { const res = await Model.find().clone(); assert.strictEqual(called, 1); assert.equal(res.length, 2); - assert.deepEqual(res.map((doc) => doc.name).sort(), [ - 'Jean-Luc Picard', - 'Will Riker', - ]); + assert.deepEqual(res.map(doc => doc.name).sort(), ['Jean-Luc Picard', 'Will Riker']); }); }); - it('casts filter according to discriminator schema if in filter (gh-8881)', async function () { - const userSchema = new Schema( - { name: String }, - { discriminatorKey: 'kind' } - ); + it('casts filter according to discriminator schema if in filter (gh-8881)', async function() { + const userSchema = new Schema({ name: String }, { discriminatorKey: 'kind' }); const User = db.model('User', userSchema); - const UserWithAge = User.discriminator( - 'UserWithAge', - new Schema({ age: Number }) - ); + + const UserWithAge = User.discriminator('UserWithAge', new Schema({ age: Number })); await UserWithAge.create({ name: 'Hafez', age: 25 }); // should cast `age` to number @@ -4022,31 +3666,26 @@ describe('Query', function () { assert.equal(user.age, 25); }); - it('casts update object according to child discriminator schema when `discriminatorKey` is present (gh-8982)', async function () { + it('casts update object according to child discriminator schema when `discriminatorKey` is present (gh-8982)', async function() { const userSchema = new Schema({}, { discriminatorKey: 'kind' }); const Person = db.model('Person', userSchema); - const Worker = Person.discriminator( - 'Worker', - new Schema({ locations: [String] }) - ); + + const Worker = Person.discriminator('Worker', new Schema({ locations: [String] })); const worker = await Worker.create({ locations: ['US'] }); // should cast `update` according to `Worker` schema - await Person.updateOne( - { _id: worker._id, kind: 'Worker' }, - { $push: { locations: 'UK' } } - ); + await Person.updateOne({ _id: worker._id, kind: 'Worker' }, { $push: { locations: 'UK' } }); const person = await Person.findOne({ _id: worker._id }); assert.deepEqual(person.locations, ['US', 'UK']); }); - it('allows disabling `setDefaultsOnInsert` (gh-8410)', function () { + it('allows disabling `setDefaultsOnInsert` (gh-8410)', function() { const schema = new Schema({ title: String, - genre: { type: String, default: 'Action' }, + genre: { type: String, default: 'Action' } }); const Movie = db.model('Movie', schema); @@ -4057,40 +3696,42 @@ describe('Query', function () { new: true, upsert: true, setDefaultsOnInsert: false, - lean: true, + lean: true }; - return Movie.deleteMany({}) - .then(() => Movie.findOneAndUpdate(query, update, options)) - .then((doc) => { + return Movie.deleteMany({}). + then(() => Movie.findOneAndUpdate(query, update, options)). + then(doc => { assert.strictEqual(doc.genre, void 0); }); }); - it('throws readable error if `$and` and `$or` contain non-objects (gh-8948)', async function () { + it('throws readable error if `$and` and `$or` contain non-objects (gh-8948)', async function() { const userSchema = new Schema({ name: String }); const Person = db.model('Person', userSchema); - let err = await Person.find({ $and: [null] }).catch((err) => err); + + let err = await Person.find({ $and: [null] }).catch(err => err); assert.equal(err.name, 'CastError'); assert.equal(err.path, '$and.0'); - err = await Person.find({ $or: [false] }).catch((err) => err); + err = await Person.find({ $or: [false] }).catch(err => err); assert.equal(err.name, 'CastError'); assert.equal(err.path, '$or.0'); - err = await Person.find({ $nor: ['not an object'] }).catch((err) => err); + err = await Person.find({ $nor: ['not an object'] }).catch(err => err); assert.equal(err.name, 'CastError'); assert.equal(err.path, '$nor.0'); }); - it('includes `undefined` in filters (gh-3944)', async function () { + it('includes `undefined` in filters (gh-3944)', async function() { const userSchema = new Schema({ name: String, pwd: String }); const Person = db.model('Person', userSchema); + await Person.create([ { name: 'test1', pwd: 'my secret' }, - { name: 'test2', pwd: null }, + { name: 'test2', pwd: null } ]); let res = await Person.findOne({ name: 'test1', pwd: void 0 }); @@ -4100,36 +3741,28 @@ describe('Query', function () { assert.equal(res.name, 'test2'); }); - it('handles push with array filters (gh-9977)', async function () { - const questionSchema = new Schema( - { - question_type: { type: String, enum: ['mcq', 'essay'] }, - }, - { discriminatorKey: 'question_type', strict: 'throw' } - ); + it('handles push with array filters (gh-9977)', async function() { + const questionSchema = new Schema({ + question_type: { type: String, enum: ['mcq', 'essay'] } + }, { discriminatorKey: 'question_type', strict: 'throw' }); - const quizSchema = new Schema( - { - quiz_title: String, - questions: [questionSchema], - }, - { strict: 'throw' } - ); + const quizSchema = new Schema({ + quiz_title: String, + questions: [questionSchema] + }, { strict: 'throw' }); const Quiz = db.model('Test', quizSchema); - const mcqQuestionSchema = new Schema( - { - text: String, - choices: [{ choice_text: String, is_correct: Boolean }], - }, - { strict: 'throw' } - ); + const mcqQuestionSchema = new Schema({ + text: String, + choices: [{ choice_text: String, is_correct: Boolean }] + }, { strict: 'throw' }); quizSchema.path('questions').discriminator('mcq', mcqQuestionSchema); const id1 = new mongoose.Types.ObjectId(); const id2 = new mongoose.Types.ObjectId(); + let quiz = await Quiz.create({ quiz_title: 'quiz', questions: [ @@ -4139,51 +3772,45 @@ describe('Query', function () { text: 'A or B?', choices: [ { choice_text: 'A', is_correct: false }, - { choice_text: 'B', is_correct: true }, - ], + { choice_text: 'B', is_correct: true } + ] }, { _id: id2, - question_type: 'mcq', - }, - ], + question_type: 'mcq' + } + ] }); - const filter = { - questions: { $elemMatch: { _id: id2, question_type: 'mcq' } }, - }; + const filter = { questions: { $elemMatch: { _id: id2, question_type: 'mcq' } } }; await Quiz.updateOne(filter, { $push: { 'questions.$.choices': { choice_text: 'choice 1', - is_correct: false, - }, - }, + is_correct: false + } + } }); quiz = await Quiz.findById(quiz); assert.equal(quiz.questions[1].choices.length, 1); assert.equal(quiz.questions[1].choices[0].choice_text, 'choice 1'); - await Quiz.updateOne( - { questions: { $elemMatch: { _id: id2 } } }, - { - $push: { - 'questions.$[q].choices': { - choice_text: 'choice 3', - is_correct: false, - }, - }, - }, - { arrayFilters: [{ 'q.question_type': 'mcq' }] } - ); + await Quiz.updateOne({ questions: { $elemMatch: { _id: id2 } } }, { + $push: { + 'questions.$[q].choices': { + choice_text: 'choice 3', + is_correct: false + } + } + }, { arrayFilters: [{ 'q.question_type': 'mcq' }] }); quiz = await Quiz.findById(quiz); assert.equal(quiz.questions[1].choices.length, 2); assert.equal(quiz.questions[1].choices[1].choice_text, 'choice 3'); }); - it('Query#pre() (gh-9784)', async function () { + it('Query#pre() (gh-9784)', async function() { const Question = db.model('Test', Schema({ answer: Number })); const q1 = Question.find({ answer: 42 }); @@ -4199,18 +3826,16 @@ describe('Query', function () { assert.equal(called.length, 1); }); - it('applies schema-level `select` on arrays (gh-10029)', function () { + it('applies schema-level `select` on arrays (gh-10029)', function() { const testSchema = new mongoose.Schema({ doesntpopulate: { type: [mongoose.Schema.Types.ObjectId], - select: false, + select: false }, - populatescorrectly: [ - { - type: mongoose.Schema.Types.ObjectId, - select: false, - }, - ], + populatescorrectly: [{ + type: mongoose.Schema.Types.ObjectId, + select: false + }] }); const Test = db.model('Test', testSchema); @@ -4220,9 +3845,9 @@ describe('Query', function () { assert.deepEqual(q._fields, { doesntpopulate: 0, populatescorrectly: 0 }); }); - it('sets `writeConcern` option correctly (gh-10009)', function () { + it('sets `writeConcern` option correctly (gh-10009)', function() { const testSchema = new mongoose.Schema({ - name: String, + name: String }); const Test = db.model('Test', testSchema); @@ -4231,103 +3856,82 @@ describe('Query', function () { assert.deepEqual(q.options.writeConcern, { w: 'majority', wtimeout: 1000 }); }); - it('no longer has the deprecation warning message with writeConcern gh-10083', async function () { + it('no longer has the deprecation warning message with writeConcern gh-10083', async function() { const MySchema = new mongoose.Schema( { _id: { type: Number, required: true }, op: { type: String, required: true }, size: { type: Number, required: true }, - totalSize: { type: Number, required: true }, + totalSize: { type: Number, required: true } }, { versionKey: false, writeConcern: { w: 'majority', j: true, - wtimeout: 15000, - }, + wtimeout: 15000 + } } ); const Test = db.model('Test', MySchema); // pops up on creation of model - const entry = await Test.create({ - _id: 12345678, - op: 'help', - size: 54, - totalSize: 104, - }); + const entry = await Test.create({ _id: 12345678, op: 'help', size: 54, totalSize: 104 }); await entry.save(); }); - it('sanitizeProjection option (gh-10243)', function () { + it('sanitizeProjection option (gh-10243)', function() { const MySchema = Schema({ name: String, email: String }); const Test = db.model('Test', MySchema); let q = Test.find().select({ email: '$name' }); assert.deepEqual(q._fields, { email: '$name' }); - q = Test.find() - .setOptions({ sanitizeProjection: true }) - .select({ email: '$name' }); + q = Test.find().setOptions({ sanitizeProjection: true }).select({ email: '$name' }); assert.deepEqual(q._fields, { email: 1 }); - q = Test.find() - .select({ email: '$name' }) - .setOptions({ sanitizeProjection: true }); + q = Test.find().select({ email: '$name' }).setOptions({ sanitizeProjection: true }); assert.deepEqual(q._fields, { email: 1 }); }); - it('sanitizeFilter option (gh-3944)', function () { + it('sanitizeFilter option (gh-3944)', function() { const MySchema = Schema({ username: String, pwd: String }); const Test = db.model('Test', MySchema); - let q = Test.find({ username: 'val', pwd: 'my secret' }).setOptions({ - sanitizeFilter: true, - }); + let q = Test.find({ username: 'val', pwd: 'my secret' }).setOptions({ sanitizeFilter: true }); q._castConditions(); assert.ifError(q.error()); assert.deepEqual(q._conditions, { username: 'val', pwd: 'my secret' }); - q = Test.find({ username: 'val', pwd: { $ne: null } }).setOptions({ - sanitizeFilter: true, - }); + q = Test.find({ username: 'val', pwd: { $ne: null } }).setOptions({ sanitizeFilter: true }); q._castConditions(); assert.ok(q.error()); assert.equal(q.error().name, 'CastError'); - q = Test.find({ - username: 'val', - pwd: mongoose.trusted({ $gt: null }), - }).setOptions({ sanitizeFilter: true }); + q = Test.find({ username: 'val', pwd: mongoose.trusted({ $gt: null }) }). + setOptions({ sanitizeFilter: true }); q._castConditions(); assert.ifError(q.error()); assert.deepEqual(q._conditions, { username: 'val', pwd: { $gt: null } }); }); - it('should not error when $not is used with $size (gh-10716)', async function () { + it('should not error when $not is used with $size (gh-10716)', async function() { const barSchema = Schema({ - bar: String, + bar: String }); const testSchema = Schema({ foo: String, bars: [barSchema] }); const Test = db.model('Zulu', testSchema); - const entry = await Test.create({ - foo: 'hello', - bars: [{ bar: 'world' }, { bar: 'world1' }], - }); + const entry = await Test.create({ foo: 'hello', bars: [{ bar: 'world' }, { bar: 'world1' }] }); await entry.save(); const foos = await Test.find({ bars: { $not: { $size: 0 } } }); assert.ok(foos); }); - it('should not error when $not is used on an array of strings (gh-11467)', async function () { + it('should not error when $not is used on an array of strings (gh-11467)', async function() { const testSchema = Schema({ names: [String] }); const Test = db.model('Test', testSchema); await Test.create([{ names: ['foo'] }, { names: ['bar'] }]); let res = await Test.find({ names: { $not: /foo/ } }); - assert.deepStrictEqual( - res.map((el) => el.names), - [['bar']] - ); + assert.deepStrictEqual(res.map(el => el.names), [['bar']]); // MongoDB server < 4.4 doesn't support `{ $not: { $regex } }`, see: // https://github.com/Automattic/mongoose/runs/5441062834?check_suite_focus=true @@ -4337,28 +3941,24 @@ describe('Query', function () { } res = await Test.find({ names: { $not: { $regex: 'foo' } } }); - assert.deepStrictEqual( - res.map((el) => el.names), - [['bar']] - ); + assert.deepStrictEqual(res.map(el => el.names), [['bar']]); }); - it('adding `exec` option does not affect the query (gh-11416)', async () => { + it('adding `exec` option does not affect the query (gh-11416)', async() => { const userSchema = new Schema({ - name: { type: String }, + name: { type: String } }); + const User = db.model('User', userSchema); const createdUser = await User.create({ name: 'Hafez' }); - const users = await User.find({ _id: createdUser._id }).setOptions({ - exec: false, - }); + const users = await User.find({ _id: createdUser._id }).setOptions({ exec: false }); assert.ok(users.length, 1); }); - it('handles queries with EJSON deserialized RegExps (gh-11597)', async function () { + it('handles queries with EJSON deserialized RegExps (gh-11597)', async function() { const testSchema = new mongoose.Schema({ - name: String, + name: String }); const Test = db.model('Test', testSchema); @@ -4372,67 +3972,55 @@ describe('Query', function () { assert.equal(result[0].name, '@foo.com'); }); - it('should return query helper supplied in schema options query property instead of undefined', function (done) { - const Model = db.model( - 'Test', - new Schema( - { - userName: { - type: String, - required: [true, 'userName is required'], - }, - }, - { - query: { - byUserName(userName) { - return this.where({ userName }); - }, - }, + it('should return query helper supplied in schema options query property instead of undefined', function(done) { + const Model = db.model('Test', new Schema({ + userName: { + type: String, + required: [true, 'userName is required'] + } + }, { + query: { + byUserName(userName) { + return this.where({ userName }); } - ) - ); + } + })); - Model.create({ userName: 'test' }, function (error) { + Model.create({ userName: 'test' }, function(error) { if (error instanceof Error) { return done(error); } - Model.find() - .byUserName('test') - .exec(function (error, docs) { - if (error instanceof Error) { - return done(error); - } - assert.equal(docs.length, 1); - assert.equal(docs[0].userName, 'test'); - done(); - }); + Model.find().byUserName('test').exec(function(error, docs) { + if (error instanceof Error) { + return done(error); + } + assert.equal(docs.length, 1); + assert.equal(docs[0].userName, 'test'); + done(); + }); }); }); - it('allows a transform option for lean on a query (gh-10423)', async function () { + it('allows a transform option for lean on a query (gh-10423)', async function() { const arraySchema = new mongoose.Schema({ - sub: String, + sub: String }); const subDoc = new mongoose.Schema({ - nickName: String, + nickName: String }); const testSchema = new mongoose.Schema({ name: String, foo: [arraySchema], - otherName: subDoc, + otherName: subDoc }); const Test = db.model('Test', testSchema); - await Test.create({ - name: 'foo', - foo: [{ sub: 'Test' }, { sub: 'Testerson' }], - otherName: { nickName: 'Bar' }, - }); + await Test.create({ name: 'foo', foo: [{ sub: 'Test' }, { sub: 'Testerson' }], otherName: { nickName: 'Bar' } }); const result = await Test.find().lean({ transform: (doc) => { delete doc._id; return doc; - }, + } }); assert.strictEqual(result[0]._id, undefined); assert.strictEqual(result[0].otherName._id, undefined); @@ -4443,7 +4031,7 @@ describe('Query', function () { transform: (doc) => { delete doc._id; return doc; - }, + } }); assert.strictEqual(single._id, undefined); assert.strictEqual(single.otherName._id, undefined); @@ -4451,17 +4039,17 @@ describe('Query', function () { assert.strictEqual(single.foo[0]._id, undefined); }); - it('handles a lean transform that deletes _id with populate (gh-12143) (gh-10423)', async function () { + it('handles a lean transform that deletes _id with populate (gh-12143) (gh-10423)', async function() { const testSchema = Schema({ name: String, user: { type: mongoose.Types.ObjectId, - ref: 'User', - }, + ref: 'User' + } }); const userSchema = Schema({ - name: String, + name: String }); const Test = db.model('Test', testSchema); @@ -4470,50 +4058,49 @@ describe('Query', function () { const user = await User.create({ name: 'John Smith' }); let test = await Test.create({ name: 'test', user }); - test = await Test.findById(test) - .populate('user') - .lean({ - transform: (doc) => { - delete doc._id; - delete doc.__v; - return doc; - }, - }); + test = await Test.findById(test).populate('user').lean({ + transform: (doc) => { + delete doc._id; + delete doc.__v; + return doc; + } + }); assert.ok(test); assert.deepStrictEqual(test, { name: 'test', - user: { name: 'John Smith' }, + user: { name: 'John Smith' } }); }); - it('skips applying default projections over slice projections (gh-11940)', async function () { + it('skips applying default projections over slice projections (gh-11940)', async function() { const commentSchema = new mongoose.Schema({ - comment: String, + comment: String }); const testSchema = new mongoose.Schema({ name: String, - comments: { type: [commentSchema], select: false }, + comments: { type: [commentSchema], select: false } }); const Test = db.model('Test', testSchema); const { _id } = await Test.create({ name: 'Test', - comments: [{ comment: 'test1' }, { comment: 'test2' }], + comments: [{ comment: 'test1' }, { comment: 'test2' }] }); const doc = await Test.findById(_id).slice('comments', [1, 1]); assert.equal(doc.comments.length, 1); assert.equal(doc.comments[0].comment, 'test2'); + }); - describe('set()', function () { - it('overwrites top-level keys if setting to undefined (gh-12155)', function () { + describe('set()', function() { + it('overwrites top-level keys if setting to undefined (gh-12155)', function() { const testSchema = new mongoose.Schema({ key: String, - prop: String, + prop: String }); const Test = db.model('Test', testSchema); @@ -4524,28 +4111,28 @@ describe('Query', function () { assert.deepEqual(update, { $set: { key: undefined }, - prop: 'foo', + prop: 'foo' }); }); }); - it('select: false is ignored for type Map (gh-12445)', async function () { + it('select: false is ignored for type Map (gh-12445)', async function() { const testSchema = new mongoose.Schema({ select: { type: Map, - of: Object, + of: Object }, doNotSelect: { type: Map, of: Object, - select: false, - }, + select: false + } }); const Test = db.model('Test', testSchema); await Test.create({ select: { key: { some: 'value' } }, - doNotSelect: { otherKey: { someOther: 'value' } }, + doNotSelect: { otherKey: { someOther: 'value' } } }); const item = await Test.findOne(); @@ -4553,14 +4140,14 @@ describe('Query', function () { assert.equal(item.doNotSelect, undefined); }); - it('Map field with select: false is selected when explicitly requested (gh-12603)', async function () { + it('Map field with select: false is selected when explicitly requested (gh-12603)', async function() { const testSchema = new mongoose.Schema({ title: String, body: { type: Map, of: { en: String, pt: String }, - select: false, - }, + select: false + } }); const Test = db.model('Test', testSchema); @@ -4568,8 +4155,8 @@ describe('Query', function () { title: 'test', body: { A: { en: 'en test A value', pt: 'pt test A value' }, - B: { en: 'en test B value', pt: 'pt test B value' }, - }, + B: { en: 'en test B value', pt: 'pt test B value' } + } }); const item = await Test.findOne({}).select('+body'); @@ -4581,7 +4168,7 @@ describe('Query', function () { assert.equal(item2.get('body.A.en'), 'en test A value'); }); - it('treats ObjectId as object with `_id` for `merge()` (gh-12325)', async function () { + it('treats ObjectId as object with `_id` for `merge()` (gh-12325)', async function() { const testSchema = new mongoose.Schema({ name: String }); const Test = db.model('Test', testSchema); const _id = new mongoose.Types.ObjectId(); @@ -4597,12 +4184,9 @@ describe('Query', function () { assert.equal(q.getFilter()._id.toHexString(), _id.toHexString()); }); - it('avoid throwing error when modifying nested field with same name as discriminator key (gh-12517)', async function () { + it('avoid throwing error when modifying nested field with same name as discriminator key (gh-12517)', async function() { const options = { discriminatorKey: 'kind', strict: 'throw' }; - const testSchema = new mongoose.Schema( - { name: String, kind: String, animals: { kind: String, world: String } }, - options - ); + const testSchema = new mongoose.Schema({ name: String, kind: String, animals: { kind: String, world: String } }, options); const Test = db.model('Test', testSchema); Test.discriminator( @@ -4612,7 +4196,7 @@ describe('Query', function () { const newItem = await Test.create({ name: 'Name', - animals: { kind: 'Kind', world: 'World' }, + animals: { kind: 'Kind', world: 'World' } }); const updatedItem = await Test.findByIdAndUpdate( @@ -4620,38 +4204,32 @@ describe('Query', function () { { $set: { name: 'Name2', - animals: { kind: 'Kind2', world: 'World2' }, - }, + animals: { kind: 'Kind2', world: 'World2' } + } }, { - new: true, + new: true } ); assert.deepEqual(updatedItem.animals, { kind: 'Kind2', world: 'World2' }); - await assert.rejects( - async () => { - await Test.findByIdAndUpdate(newItem._id, { + await assert.rejects(async() => { + await Test.findByIdAndUpdate( + newItem._id, + { $set: { name: 'Name2', - kind: 'Kind2', - }, - }); - }, - { - message: - 'Can\'t modify discriminator key "kind" on discriminator model', - } - ); + kind: 'Kind2' + } + } + ); + }, { message: 'Can\'t modify discriminator key "kind" on discriminator model' }); }); - it('avoid throwing error when modifying field with same name as nested discriminator key (gh-12517)', async function () { + it('avoid throwing error when modifying field with same name as nested discriminator key (gh-12517)', async function() { const options = { discriminatorKey: 'animals.kind', strict: 'throw' }; - const testSchema = new mongoose.Schema( - { name: String, kind: String, animals: { kind: String, world: String } }, - options - ); + const testSchema = new mongoose.Schema({ name: String, kind: String, animals: { kind: String, world: String } }, options); const Test = db.model('Test', testSchema); Test.discriminator( @@ -4662,7 +4240,7 @@ describe('Query', function () { const newItem = await Test.create({ name: 'Name', kind: 'Kind', - animals: { world: 'World' }, + animals: { world: 'World' } }); const updatedItem = await Test.findByIdAndUpdate( @@ -4670,33 +4248,30 @@ describe('Query', function () { { $set: { name: 'Name2', - kind: 'Kind2', - }, + kind: 'Kind2' + } }, { - new: true, + new: true } ); assert.equal(updatedItem.name, 'Name2'); assert.equal(updatedItem.kind, 'Kind2'); - await assert.rejects( - async () => { - await Test.findByIdAndUpdate(newItem._id, { + await assert.rejects(async() => { + await Test.findByIdAndUpdate( + newItem._id, + { $set: { - animals: { kind: 'Kind2', world: 'World2' }, - }, - }); - }, - { - message: - 'Can\'t modify discriminator key "animals.kind" on discriminator model', - } - ); + animals: { kind: 'Kind2', world: 'World2' } + } + } + ); + }, { message: 'Can\'t modify discriminator key "animals.kind" on discriminator model' }); }); - it('global strictQuery should work if applied after schema creation (gh-12703)', async () => { + it('global strictQuery should work if applied after schema creation (gh-12703)', async() => { const m = new mongoose.Mongoose(); await m.connect(start.uri); @@ -4708,13 +4283,13 @@ describe('Query', function () { m.set('strictQuery', false); await Test.create({ - title: 'chimichanga', + title: 'chimichanga' }); await Test.create({ - title: 'burrito bowl', + title: 'burrito bowl' }); await Test.create({ - title: 'taco supreme', + title: 'taco supreme' }); const cond = { @@ -4722,16 +4297,16 @@ describe('Query', function () { { title: { $regex: 'urri', - $options: 'i', - }, + $options: 'i' + } }, { name: { $regex: 'urri', - $options: 'i', - }, - }, - ], + $options: 'i' + } + } + ] }; const found = await Test.find(cond); @@ -4739,7 +4314,7 @@ describe('Query', function () { assert.strictEqual(found[0].title, 'burrito bowl'); }); - it('update operation should remove fields set to undefined (gh-12794)', async () => { + it('update operation should remove fields set to undefined (gh-12794)', async() => { const m = new mongoose.Mongoose(); await m.connect(start.uri); @@ -4749,19 +4324,19 @@ describe('Query', function () { const Test = m.model('test', schema); const doc = await Test.create({ - title: 'test', + title: 'test' }); assert.strictEqual(doc.title, 'test'); const updatedDoc = await Test.findOneAndUpdate( { - _id: doc._id, + _id: doc._id }, { title: undefined }, { returnOriginal: false } ); - + assert.ok(updatedDoc.title === undefined); }); }); From dba965e3ac68af8a23147ddea5bc1f0cc1584b08 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Thu, 15 Dec 2022 14:00:17 -0500 Subject: [PATCH 15/23] fix(update): handle embedded discriminators when casting array filters Fix #12565 --- lib/helpers/update/castArrayFilters.js | 56 ++++++++++++++------ test/helpers/update.castArrayFilters.test.js | 49 +++++++++++++++++ 2 files changed, 90 insertions(+), 15 deletions(-) diff --git a/lib/helpers/update/castArrayFilters.js b/lib/helpers/update/castArrayFilters.js index 76ce94b03b3..163e33be14c 100644 --- a/lib/helpers/update/castArrayFilters.js +++ b/lib/helpers/update/castArrayFilters.js @@ -37,14 +37,36 @@ function _castArrayFilters(arrayFilters, schema, strictQuery, updatedPathsByFilt if (filter == null) { throw new Error(`Got null array filter in ${arrayFilters}`); } - for (const key of Object.keys(filter)) { - if (key === '$and' || key === '$or') { + const keys = Object.keys(filter).filter(key => filter[key] != null); + if (keys.length === 0) { + continue; + } + + const firstKey = keys[0]; + if (firstKey === '$and' || firstKey === '$or') { + for (const key of keys) { _castArrayFilters(filter[key], schema, strictQuery, updatedPathsByFilter, query); - continue; - } - if (filter[key] == null) { - continue; } + continue; + } + const dot = firstKey.indexOf('.'); + const filterWildcardPath = dot === -1 ? firstKey : firstKey.substring(0, dot); + if (updatedPathsByFilter[filterWildcardPath] == null) { + continue; + } + const baseFilterPath = cleanPositionalOperators( + updatedPathsByFilter[filterWildcardPath] + ); + + const baseSchematype = getPath(schema, baseFilterPath); + let filterBaseSchema = baseSchematype != null ? baseSchematype.schema : null; + if (filterBaseSchema != null && + filterBaseSchema.discriminators != null && + filter[filterWildcardPath + '.' + filterBaseSchema.options.discriminatorKey]) { + filterBaseSchema = filterBaseSchema.discriminators[filter[filterWildcardPath + '.' + filterBaseSchema.options.discriminatorKey]] || filterBaseSchema; + } + + for (const key of keys) { if (updatedPathsByFilter[key] === null) { continue; } @@ -52,21 +74,25 @@ function _castArrayFilters(arrayFilters, schema, strictQuery, updatedPathsByFilt continue; } const dot = key.indexOf('.'); - let filterPath = dot === -1 ? - updatedPathsByFilter[key] + '.0' : - updatedPathsByFilter[key.substring(0, dot)] + '.0' + key.substring(dot); - if (filterPath == null) { - throw new Error(`Filter path not found for ${key}`); + + let filterPathRelativeToBase = dot === -1 ? null : key.substring(dot); + let schematype; + if (filterPathRelativeToBase == null || filterBaseSchema == null) { + schematype = baseSchematype; + } else { + // If there are multiple array filters in the path being updated, make sure + // to replace them so we can get the schema path. + filterPathRelativeToBase = cleanPositionalOperators(filterPathRelativeToBase); + schematype = getPath(filterBaseSchema, filterPathRelativeToBase); } - // If there are multiple array filters in the path being updated, make sure - // to replace them so we can get the schema path. - filterPath = cleanPositionalOperators(filterPath); - const schematype = getPath(schema, filterPath); if (schematype == null) { if (!strictQuery) { return; } + const filterPath = filterPathRelativeToBase == null ? + baseFilterPath + '.0' : + baseFilterPath + '.0' + filterPathRelativeToBase; // For now, treat `strictQuery = true` and `strictQuery = 'throw'` as // equivalent for casting array filters. `strictQuery = true` doesn't // quite work in this context because we never want to silently strip out diff --git a/test/helpers/update.castArrayFilters.test.js b/test/helpers/update.castArrayFilters.test.js index 6baad3f8474..d132663b590 100644 --- a/test/helpers/update.castArrayFilters.test.js +++ b/test/helpers/update.castArrayFilters.test.js @@ -262,4 +262,53 @@ describe('castArrayFilters', function() { castArrayFilters(q); }, /Could not find path "arr\.0\.notInSchema" in schema/); }); + + it('handles embedded discriminators (gh-12565)', function() { + const elementSchema = new Schema( + { elementType: String }, + { discriminatorKey: 'elementType' } + ); + const versionSchema = new Schema( + { version: Number, elements: [elementSchema] }, + { strictQuery: 'throw' } + ); + versionSchema.path('elements').discriminator( + 'Graph', + new Schema({ + number: Number, + curves: [{ line: { label: String, type: String, number: String, latLong: [Number], controller: String } }] + }) + ); + + const testSchema = new Schema({ versions: [versionSchema] }); + + const q = new Query(); + q.schema = testSchema; + + const p = { + $push: { + 'versions.$[version].elements.$[element].curves': { + line: { + label: 'CC110_Ligne 02', + type: 'numerique', + number: '30', + latLong: [44, 8], + controller: 'CC110' + } + } + } + }; + const opts = { + arrayFilters: [ + { + 'element.elementType': 'Graph', + 'element.number': '1' + } + ] + }; + q.updateOne({}, p, opts); + castArrayFilters(q); + + assert.strictEqual(q.options.arrayFilters[0]['element.number'], 1); + }); }); From 552ea2bb98c3042c887893a64e84f1e21445694f Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Thu, 15 Dec 2022 14:07:14 -0500 Subject: [PATCH 16/23] docs: make `Document.prototype.$clone()` public --- lib/document.js | 2 +- types/document.d.ts | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/document.js b/lib/document.js index 73e2fdedbb6..1a6e7be05f5 100644 --- a/lib/document.js +++ b/lib/document.js @@ -4655,7 +4655,7 @@ Document.prototype.getChanges = function() { * Returns a copy of this document with a deep clone of `_doc` and `$__`. * * @return {Document} a copy of this document - * @api private + * @api public * @method $clone * @memberOf Document * @instance diff --git a/types/document.d.ts b/types/document.d.ts index 0d8f085def3..f43db5c34c8 100644 --- a/types/document.d.ts +++ b/types/document.d.ts @@ -28,6 +28,9 @@ declare module 'mongoose' { /** Assert that a given path or paths is populated. Throws an error if not populated. */ $assertPopulated(path: string | string[], values?: Partial): Omit & Paths; + /** Returns a deep clone of this document */ + $clone(): this; + /* Get all subdocs (by bfs) */ $getAllSubdocs(): Document[]; From 24da2a4e122ab321c1b2ad684fa3f0f219421bf2 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Thu, 15 Dec 2022 14:41:05 -0500 Subject: [PATCH 17/23] fix(populate): avoid calling `transform` if there's no populate results and using lean Fix #12739 --- lib/helpers/populate/assignVals.js | 2 ++ test/model.populate.test.js | 30 +++++++++++++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/lib/helpers/populate/assignVals.js b/lib/helpers/populate/assignVals.js index da40f396e2a..92f0ebecd05 100644 --- a/lib/helpers/populate/assignVals.js +++ b/lib/helpers/populate/assignVals.js @@ -253,6 +253,8 @@ function valueFilter(val, assignmentOpts, populateOptions, allIds) { const _allIds = Array.isArray(allIds) ? allIds[i] : allIds; if (!isPopulatedObject(subdoc) && (!populateOptions.retainNullValues || subdoc != null) && !userSpecifiedTransform) { continue; + } else if (!populateOptions.retainNullValues && subdoc == null) { + continue; } else if (userSpecifiedTransform) { subdoc = transform(isPopulatedObject(subdoc) ? subdoc : null, _allIds); } diff --git a/test/model.populate.test.js b/test/model.populate.test.js index a2700930832..c26b2741006 100644 --- a/test/model.populate.test.js +++ b/test/model.populate.test.js @@ -9942,7 +9942,6 @@ describe('model: populate:', function() { const Child = db.model('Child', Schema({ name: String })); - const children = await Child.create([{ name: 'Luke' }, { name: 'Leia' }]); let p = await Parent.create({ name: 'Anakin', @@ -10024,6 +10023,35 @@ describe('model: populate:', function() { assert.equal(called[0].id.toHexString(), newId.toHexString()); }); + it('avoids calling `transform()` with `lean()` when no results (gh-12739)', async function() { + const parentSchema = new Schema({ title: String }); + const childSchema = new Schema({ + title: String, + parent: { type: mongoose.Schema.Types.ObjectId, ref: 'Parent' } + }); + parentSchema.virtual('children', { + ref: 'Child', + localField: '_id', + foreignField: 'parent' + }); + const Parent = db.model('Parent', parentSchema); + const Child = db.model('Child', childSchema); + + await Parent.create({ title: 'parent' }); + await Child.create({ title: 'child' }); + const p = await Parent.find().lean().populate({ + path: 'children', + match: { title: 'child' }, + select: '-__v', + strictPopulate: false, + transform: doc => { + return doc; + } + }); + assert.equal(p.length, 1); + assert.deepStrictEqual(p[0].children, []); + }); + it('transform to primitive (gh-10064)', async function() { const Child = db.model('Child', mongoose.Schema({ name: String })); const Parent = db.model('Parent', mongoose.Schema({ From 99b6cca423b4f48ba7405063b11f703a2c47696c Mon Sep 17 00:00:00 2001 From: Luca Pizzini Date: Fri, 16 Dec 2022 09:21:10 +0100 Subject: [PATCH 18/23] made findOneAndUpdate result lean() for assertion --- test/query.test.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/query.test.js b/test/query.test.js index 3898bfc1422..f291c5d226f 100644 --- a/test/query.test.js +++ b/test/query.test.js @@ -4335,8 +4335,8 @@ describe('Query', function() { }, { title: undefined }, { returnOriginal: false } - ); + ).lean(); - assert.ok(updatedDoc.title === undefined); + assert.ok('title' in updatedDoc === false); }); }); From 32ee09a57510a44e1428342620c621ea1ad37122 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Fri, 16 Dec 2022 15:00:24 -0500 Subject: [PATCH 19/23] Update index.md --- docs/index.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/index.md b/docs/index.md index 505ab69f376..c791af2cddc 100644 --- a/docs/index.md +++ b/docs/index.md @@ -34,7 +34,7 @@ main().catch(err => console.log(err)); async function main() { await mongoose.connect('mongodb://127.0.0.1:27017/test'); - // use `await mongoose.connect('mongodb://user:password@localhost:27017/test');` if your database has auth enabled + // use `await mongoose.connect('mongodb://user:password@127.0.0.1:27017/test');` if your database has auth enabled } ``` From 44a0fb61b1afd53ea59c0f13d7675296b69d97b4 Mon Sep 17 00:00:00 2001 From: Luca Pizzini Date: Sat, 17 Dec 2022 10:03:23 +0100 Subject: [PATCH 20/23] docs(mongoose): Added missing options to set fix #12808 --- lib/index.js | 42 ++++++++++++++++++++++-------------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/lib/index.js b/lib/index.js index ec2a5d733b1..e6dcb7aaa9c 100644 --- a/lib/index.js +++ b/lib/index.js @@ -198,26 +198,28 @@ Mongoose.prototype.setDriver = function setDriver(driver) { * mongoose.set({ debug: true, autoIndex: false }); // set multiple options at once * * Currently supported options are: - * - 'applyPluginsToChildSchemas': `true` by default. Set to false to skip applying global plugins to child schemas - * - 'applyPluginsToDiscriminators': `false` by default. Set to true to apply global plugins to discriminator schemas. This typically isn't necessary because plugins are applied to the base schema and discriminators copy all middleware, methods, statics, and properties from the base schema. - * - 'autoCreate': Set to `true` to make Mongoose call [`Model.createCollection()`](/docs/api/model.html#model_Model-createCollection) automatically when you create a model with `mongoose.model()` or `conn.model()`. This is useful for testing transactions, change streams, and other features that require the collection to exist. - * - 'autoIndex': `true` by default. Set to false to disable automatic index creation for all models associated with this Mongoose instance. - * - 'debug': If `true`, prints the operations mongoose sends to MongoDB to the console. If a writable stream is passed, it will log to that stream, without colorization. If a callback function is passed, it will receive the collection name, the method name, then all arguments passed to the method. For example, if you wanted to replicate the default logging, you could output from the callback `Mongoose: ${collectionName}.${methodName}(${methodArgs.join(', ')})`. - * - 'returnOriginal': If `false`, changes the default `returnOriginal` option to `findOneAndUpdate()`, `findByIdAndUpdate`, and `findOneAndReplace()` to false. This is equivalent to setting the `new` option to `true` for `findOneAndX()` calls by default. Read our [`findOneAndUpdate()` tutorial](/docs/tutorials/findoneandupdate.html) for more information. - * - 'bufferCommands': enable/disable mongoose's buffering mechanism for all connections and models - * - 'cloneSchemas': `false` by default. Set to `true` to `clone()` all schemas before compiling into a model. - * - 'timestamps.createdAt.immutable': `true` by default. If `false`, it will change the `createdAt` field to be [`immutable: false`](https://mongoosejs.com/docs/api/schematype.html#schematype_SchemaType-immutable) which means you can update the `createdAt` - * - 'maxTimeMS': If set, attaches [maxTimeMS](https://docs.mongodb.com/manual/reference/operator/meta/maxTimeMS/) to every query - * - 'objectIdGetter': `true` by default. Mongoose adds a getter to MongoDB ObjectId's called `_id` that returns `this` for convenience with populate. Set this to false to remove the getter. - * - 'overwriteModels': Set to `true` to default to overwriting models with the same name when calling `mongoose.model()`, as opposed to throwing an `OverwriteModelError`. - * - 'returnOriginal': If `false`, changes the default `returnOriginal` option to `findOneAndUpdate()`, `findByIdAndUpdate`, and `findOneAndReplace()` to false. This is equivalent to setting the `new` option to `true` for `findOneAndX()` calls by default. Read our [`findOneAndUpdate()` tutorial](/docs/tutorials/findoneandupdate.html) for more information. - * - 'runValidators': `false` by default. Set to true to enable [update validators](/docs/validation.html#update-validators) for all validators by default. - * - 'sanitizeFilter': `false` by default. Set to true to enable the [sanitization of the query filters](/docs/api/mongoose.html#mongoose_Mongoose-sanitizeFilter) against query selector injection attacks by wrapping any nested objects that have a property whose name starts with `$` in a `$eq`. - * - 'selectPopulatedPaths': `true` by default. Set to false to opt out of Mongoose adding all fields that you `populate()` to your `select()`. The schema-level option `selectPopulatedPaths` overwrites this one. - * - 'strict': `true` by default, may be `false`, `true`, or `'throw'`. Sets the default strict mode for schemas. - * - 'strictQuery': same value as 'strict' by default (`true`), may be `false`, `true`, or `'throw'`. Sets the default [strictQuery](/docs/guide.html#strictQuery) mode for schemas. The default value will be switched back to `false` in Mongoose 7, use `mongoose.set('strictQuery', false);` if you want to prepare for the change. - * - 'toJSON': `{ transform: true, flattenDecimals: true }` by default. Overwrites default objects to [`toJSON()`](/docs/api/document.html#document_Document-toJSON), for determining how Mongoose documents get serialized by `JSON.stringify()` - * - 'toObject': `{ transform: true, flattenDecimals: true }` by default. Overwrites default objects to [`toObject()`](/docs/api/document.html#document_Document-toObject) + * - `allowDiskUse`: Set to `true` to set `allowDiskUse` to true to all aggregation operations by default. + * - `applyPluginsToChildSchemas`: `true` by default. Set to false to skip applying global plugins to child schemas + * - `applyPluginsToDiscriminators`: `false` by default. Set to true to apply global plugins to discriminator schemas. This typically isn't necessary because plugins are applied to the base schema and discriminators copy all middleware, methods, statics, and properties from the base schema. + * - `autoCreate`: Set to `true` to make Mongoose call [`Model.createCollection()`](/docs/api/model.html#model_Model-createCollection) automatically when you create a model with `mongoose.model()` or `conn.model()`. This is useful for testing transactions, change streams, and other features that require the collection to exist. + * - `autoIndex`: `true` by default. Set to false to disable automatic index creation for all models associated with this Mongoose instance. + * - `bufferCommands`: enable/disable mongoose's buffering mechanism for all connections and models + * - `bufferTimeoutMS`: If bufferCommands is on, this option sets the maximum amount of time Mongoose buffering will wait before throwing an error. If not specified, Mongoose will use 10000 (10 seconds). + * - `cloneSchemas`: `false` by default. Set to `true` to `clone()` all schemas before compiling into a model. + * - `debug`: If `true`, prints the operations mongoose sends to MongoDB to the console. If a writable stream is passed, it will log to that stream, without colorization. If a callback function is passed, it will receive the collection name, the method name, then all arguments passed to the method. For example, if you wanted to replicate the default logging, you could output from the callback `Mongoose: ${collectionName}.${methodName}(${methodArgs.join(', ')})`. + * - `id`: If `true`, adds a `id` virtual to all schemas unless overwritten on a per-schema basis. + * - `timestamps.createdAt.immutable`: `true` by default. If `false`, it will change the `createdAt` field to be [`immutable: false`](https://mongoosejs.com/docs/api/schematype.html#schematype_SchemaType-immutable) which means you can update the `createdAt` + * - `maxTimeMS`: If set, attaches [maxTimeMS](https://docs.mongodb.com/manual/reference/operator/meta/maxTimeMS/) to every query + * - `objectIdGetter`: `true` by default. Mongoose adds a getter to MongoDB ObjectId's called `_id` that returns `this` for convenience with populate. Set this to false to remove the getter. + * - `overwriteModels`: Set to `true` to default to overwriting models with the same name when calling `mongoose.model()`, as opposed to throwing an `OverwriteModelError`. + * - `returnOriginal`: If `false`, changes the default `returnOriginal` option to `findOneAndUpdate()`, `findByIdAndUpdate`, and `findOneAndReplace()` to false. This is equivalent to setting the `new` option to `true` for `findOneAndX()` calls by default. Read our [`findOneAndUpdate()` tutorial](/docs/tutorials/findoneandupdate.html) for more information. + * - `runValidators`: `false` by default. Set to true to enable [update validators](/docs/validation.html#update-validators) for all validators by default. + * - `sanitizeFilter`: `false` by default. Set to true to enable the [sanitization of the query filters](/docs/api/mongoose.html#mongoose_Mongoose-sanitizeFilter) against query selector injection attacks by wrapping any nested objects that have a property whose name starts with `$` in a `$eq`. + * - `selectPopulatedPaths`: `true` by default. Set to false to opt out of Mongoose adding all fields that you `populate()` to your `select()`. The schema-level option `selectPopulatedPaths` overwrites this one. + * - `strict`: `true` by default, may be `false`, `true`, or `'throw'`. Sets the default strict mode for schemas. + * - `strictQuery`: same value as 'strict' by default (`true`), may be `false`, `true`, or `'throw'`. Sets the default [strictQuery](/docs/guide.html#strictQuery) mode for schemas. The default value will be switched back to `false` in Mongoose 7, use `mongoose.set('strictQuery', false);` if you want to prepare for the change. + * - `toJSON`: `{ transform: true, flattenDecimals: true }` by default. Overwrites default objects to [`toJSON()`](/docs/api/document.html#document_Document-toJSON), for determining how Mongoose documents get serialized by `JSON.stringify()` + * - `toObject`: `{ transform: true, flattenDecimals: true }` by default. Overwrites default objects to [`toObject()`](/docs/api/document.html#document_Document-toObject) * * @param {String|Object} key The name of the option or a object of multiple key-value pairs * @param {String|Function|Boolean} value The value of the option, unused if "key" is a object From 694d9146581a6d4ba0bab9ca932884ee725a45c7 Mon Sep 17 00:00:00 2001 From: hasezoey Date: Sat, 17 Dec 2022 12:02:23 +0100 Subject: [PATCH 21/23] chore: replace many occurrences of "localhost" with "127.0.0.1" --- CONTRIBUTING.md | 2 +- README.md | 6 ++--- benchmarks/benchjs/delete.js | 4 ++-- benchmarks/benchjs/insert.js | 4 ++-- benchmarks/benchjs/multiop.js | 4 ++-- benchmarks/benchjs/population.js | 2 +- benchmarks/benchjs/read.js | 4 ++-- benchmarks/benchjs/update.js | 4 ++-- benchmarks/mem.js | 2 +- benchmarks/populate.js | 2 +- docs/connections.md | 16 ++++++------- docs/guide.md | 4 ++-- docs/migrating_to_5.md | 8 +++---- docs/migrating_to_6.md | 2 +- docs/models.md | 4 ++-- docs/populate.md | 4 ++-- docs/tutorials/ssl.md | 14 +++++------ docs/typescript.md | 2 +- docs/typescript/query-helpers.md | 4 ++-- examples/aggregate/aggregate.js | 2 +- examples/doc-methods.js | 4 ++-- examples/express/connection-sharing/README.md | 2 +- examples/express/connection-sharing/app.js | 4 ++-- examples/geospatial/geoJSONexample.js | 2 +- examples/geospatial/geospatial.js | 2 +- examples/globalschemas/gs_example.js | 2 +- examples/lean/lean.js | 2 +- examples/mapreduce/mapreduce.js | 2 +- .../population-across-three-collections.js | 2 +- examples/population/population-basic.js | 4 ++-- .../population/population-of-existing-doc.js | 4 ++-- .../population-of-multiple-existing-docs.js | 4 ++-- examples/population/population-options.js | 4 ++-- .../population/population-plain-objects.js | 4 ++-- examples/promises/promise.js | 2 +- examples/querybuilder/querybuilder.js | 2 +- examples/redis-todo/db/index.js | 2 +- examples/replicasets/replica-sets.js | 2 +- examples/statics/statics.js | 2 +- index.pug | 2 +- lib/connection.js | 24 +++++++++---------- lib/index.js | 16 ++++++------- scripts/static.js | 2 +- test/shard.test.js | 2 +- test/types/base.test.ts | 2 +- test/types/connect.test.ts | 12 +++++----- test/types/connection.test.ts | 24 +++++++++---------- tools/auth.js | 4 ++-- tools/sharded.js | 8 +++---- 49 files changed, 121 insertions(+), 121 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c3a57dbb27d..4b5246b66ce 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -58,7 +58,7 @@ If you'd like to preview your documentation changes, first commit your changes t * `npm install` * `npm run docs:view` -Visit `http://localhost:8089` and you should see the docs with your local changes. Make sure you `npm run docs:clean` before committing, because automated generated files to `docs/*` should **not** be in PRs. +Visit `http://127.0.0.1:8089` and you should see the docs with your local changes. Make sure you `npm run docs:clean` before committing, because automated generated files to `docs/*` should **not** be in PRs. #### Documentation Style Guidelines diff --git a/README.md b/README.md index cda03d3edbf..d62c95b6c60 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ const require = createRequire(import.meta.url); const mongoose = require('mongoose'); -mongoose.connect('mongodb://localhost:27017/test') +mongoose.connect('mongodb://127.0.0.1:27017/test') .then(() => console.log('Connected!')); ``` @@ -91,12 +91,12 @@ First, we need to define a connection. If your app uses only one database, you s Both `connect` and `createConnection` take a `mongodb://` URI, or the parameters `host, database, port, options`. ```js -await mongoose.connect('mongodb://localhost/my_database'); +await mongoose.connect('mongodb://127.0.0.1/my_database'); ``` Once connected, the `open` event is fired on the `Connection` instance. If you're using `mongoose.connect`, the `Connection` is `mongoose.connection`. Otherwise, `mongoose.createConnection` return value is a `Connection`. -**Note:** _If the local connection fails then try using 127.0.0.1 instead of localhost. Sometimes issues may arise when the local hostname has been changed._ +**Note:** _If the local connection fails then try using 127.0.0.1 instead of 127.0.0.1. Sometimes issues may arise when the local hostname has been changed._ **Important!** Mongoose buffers all the commands until it's connected to the database. This means that you don't have to wait until it connects to MongoDB in order to define models, run queries, etc. diff --git a/benchmarks/benchjs/delete.js b/benchmarks/benchjs/delete.js index 705c8091fe1..1d717f7f6e3 100644 --- a/benchmarks/benchjs/delete.js +++ b/benchmarks/benchjs/delete.js @@ -17,11 +17,11 @@ const mongoClient = require('mongodb').MongoClient; * These are all the benchmark tests for deleting data */ -mongoose.connect('mongodb://localhost/mongoose-bench', function (err) { +mongoose.connect('mongodb://127.0.0.1/mongoose-bench', function (err) { if (err) { throw err; } - mongoClient.connect('mongodb://localhost', function (err, client) { + mongoClient.connect('mongodb://127.0.0.1', function (err, client) { if (err) { throw err; } diff --git a/benchmarks/benchjs/insert.js b/benchmarks/benchjs/insert.js index 7b13f90dcde..cd01bfb6069 100644 --- a/benchmarks/benchjs/insert.js +++ b/benchmarks/benchjs/insert.js @@ -19,12 +19,12 @@ const ObjectId = Schema.Types.ObjectId; * These are all the benchmark tests for inserting data */ -mongoose.connect('mongodb://localhost/mongoose-bench', function (err) { +mongoose.connect('mongodb://127.0.0.1/mongoose-bench', function (err) { if (err) { throw err; } mongoClient.connect( - 'mongodb://localhost/mongoose-bench', + 'mongodb://127.0.0.1/mongoose-bench', function (err, client) { if (err) { throw err; diff --git a/benchmarks/benchjs/multiop.js b/benchmarks/benchjs/multiop.js index bfe540705fd..c3f73d1f730 100644 --- a/benchmarks/benchjs/multiop.js +++ b/benchmarks/benchjs/multiop.js @@ -19,11 +19,11 @@ const utils = require('../../lib/utils.js'); * These are all the benchmark tests for mixed data operations */ -mongoose.connect('mongodb://localhost/mongoose-bench', function (err) { +mongoose.connect('mongodb://127.0.0.1/mongoose-bench', function (err) { if (err) { throw err; } - mongoClient.connect('mongodb://localhost', function (err, client) { + mongoClient.connect('mongodb://127.0.0.1', function (err, client) { if (err) { throw err; } diff --git a/benchmarks/benchjs/population.js b/benchmarks/benchjs/population.js index 81b46ed2799..dc55ac1cae9 100644 --- a/benchmarks/benchjs/population.js +++ b/benchmarks/benchjs/population.js @@ -18,7 +18,7 @@ const utils = require('../../lib/utils.js'); * These are all the benchmark tests for population ops */ -mongoose.connect('mongodb://localhost/mongoose-bench', function (err) { +mongoose.connect('mongodb://127.0.0.1/mongoose-bench', function (err) { if (err) { throw err; } diff --git a/benchmarks/benchjs/read.js b/benchmarks/benchjs/read.js index e97e2fab842..35d39b90916 100644 --- a/benchmarks/benchjs/read.js +++ b/benchmarks/benchjs/read.js @@ -20,11 +20,11 @@ const utils = require('../../lib/utils.js'); * These are all the benchmark tests for reading data */ -mongoose.connect('mongodb://localhost/mongoose-bench', function (err) { +mongoose.connect('mongodb://127.0.0.1/mongoose-bench', function (err) { if (err) { throw err; } - mongoClient.connect('mongodb://localhost', function (err, client) { + mongoClient.connect('mongodb://127.0.0.1', function (err, client) { if (err) { throw err; } diff --git a/benchmarks/benchjs/update.js b/benchmarks/benchjs/update.js index cb745742a55..4447339cf65 100644 --- a/benchmarks/benchjs/update.js +++ b/benchmarks/benchjs/update.js @@ -20,11 +20,11 @@ const utils = require('../../lib/utils.js'); * These are all the benchmark tests for updating data */ -mongoose.connect('mongodb://localhost/mongoose-bench', function (err) { +mongoose.connect('mongodb://127.0.0.1/mongoose-bench', function (err) { if (err) { throw err; } - mongoClient.connect('mongodb://localhost', function (err, client) { + mongoClient.connect('mongodb://127.0.0.1', function (err, client) { if (err) { throw err; } diff --git a/benchmarks/mem.js b/benchmarks/mem.js index 1864562056d..c73acac33e4 100644 --- a/benchmarks/mem.js +++ b/benchmarks/mem.js @@ -4,7 +4,7 @@ const mongoose = require('../'); const Schema = mongoose.Schema; -mongoose.connect('mongodb://localhost/mongoose-bench'); +mongoose.connect('mongodb://127.0.0.1/mongoose-bench'); const DocSchema = new Schema({ title: String diff --git a/benchmarks/populate.js b/benchmarks/populate.js index a5f7476b04f..2be29e72e0e 100644 --- a/benchmarks/populate.js +++ b/benchmarks/populate.js @@ -18,7 +18,7 @@ const B = mongoose.model('B', Schema({ let start; let count = 0; -mongoose.connect('mongodb://localhost/mongoose-bench', function(err) { +mongoose.connect('mongodb://127.0.0.1/mongoose-bench', function(err) { if (err) { return done(err); } diff --git a/docs/connections.md b/docs/connections.md index a16b9f6161c..b65f6100e6f 100644 --- a/docs/connections.md +++ b/docs/connections.md @@ -3,7 +3,7 @@ You can connect to MongoDB with the `mongoose.connect()` method. ```javascript -mongoose.connect('mongodb://localhost:27017/myapp'); +mongoose.connect('mongodb://127.0.0.1:27017/myapp'); ``` This is the minimum needed to connect the `myapp` database running locally @@ -39,7 +39,7 @@ Mongoose lets you start using your models immediately, without waiting for mongoose to establish a connection to MongoDB. ```javascript -mongoose.connect('mongodb://localhost:27017/myapp'); +mongoose.connect('mongodb://127.0.0.1:27017/myapp'); const MyModel = mongoose.model('Test', new Schema({ name: String })); // Works MyModel.findOne(function(error, result) { /* ... */ }); @@ -56,7 +56,7 @@ const MyModel = mongoose.model('Test', new Schema({ name: String })); MyModel.findOne(function(error, result) { /* ... */ }); setTimeout(function() { - mongoose.connect('mongodb://localhost:27017/myapp'); + mongoose.connect('mongodb://127.0.0.1:27017/myapp'); }, 60000); ``` @@ -101,12 +101,12 @@ There are two classes of errors that can occur with a Mongoose connection. To handle initial connection errors, you should use `.catch()` or `try/catch` with async/await. ```javascript -mongoose.connect('mongodb://localhost:27017/test'). +mongoose.connect('mongodb://127.0.0.1:27017/test'). catch(error => handleError(error)); // Or: try { - await mongoose.connect('mongodb://localhost:27017/test'); + await mongoose.connect('mongodb://127.0.0.1:27017/test'); } catch (error) { handleError(error); } @@ -201,9 +201,9 @@ driver. You **can't** set Mongoose-specific options like `bufferCommands` in the query string. ```javascript -mongoose.connect('mongodb://localhost:27017/test?connectTimeoutMS=1000&bufferCommands=false&authSource=otherdb'); +mongoose.connect('mongodb://127.0.0.1:27017/test?connectTimeoutMS=1000&bufferCommands=false&authSource=otherdb'); // The above is equivalent to: -mongoose.connect('mongodb://localhost:27017/test', { +mongoose.connect('mongodb://127.0.0.1:27017/test', { connectTimeoutMS: 1000 // Note that mongoose will **not** pull `bufferCommands` from the query string }); @@ -453,7 +453,7 @@ using your connection options: mongoose.createConnection(uri, { maxPoolSize: 10 }); // With connection string options -const uri = 'mongodb://localhost:27017/test?maxPoolSize=10'; +const uri = 'mongodb://127.0.0.1:27017/test?maxPoolSize=10'; mongoose.createConnection(uri); ``` diff --git a/docs/guide.md b/docs/guide.md index c11bede3e23..09d57b34363 100644 --- a/docs/guide.md +++ b/docs/guide.md @@ -274,9 +274,9 @@ While nice for development, it is recommended this behavior be disabled in produ Disable the behavior by setting the `autoIndex` option of your schema to `false`, or globally on the connection by setting the option `autoIndex` to `false`. ```javascript -mongoose.connect('mongodb://user:pass@localhost:port/database', { autoIndex: false }); +mongoose.connect('mongodb://user:pass@127.0.0.1:port/database', { autoIndex: false }); // or -mongoose.createConnection('mongodb://user:pass@localhost:port/database', { autoIndex: false }); +mongoose.createConnection('mongodb://user:pass@127.0.0.1:port/database', { autoIndex: false }); // or mongoose.set('autoIndex', false); // or diff --git a/docs/migrating_to_5.md b/docs/migrating_to_5.md index fcf4c0080d0..c909efaefd7 100644 --- a/docs/migrating_to_5.md +++ b/docs/migrating_to_5.md @@ -70,10 +70,10 @@ MyModel.find().exec(function() { // Worked in mongoose 4. Does **not** work in mongoose 5, `mongoose.connect()` // now returns a promise consistently. This is to avoid the horrible things // we've done to allow mongoose to be a thenable that resolves to itself. -mongoose.connect('mongodb://localhost:27017/test').model('Test', new Schema({})); +mongoose.connect('mongodb://127.0.0.1:27017/test').model('Test', new Schema({})); // Do this instead -mongoose.connect('mongodb://localhost:27017/test'); +mongoose.connect('mongodb://127.0.0.1:27017/test'); mongoose.model('Test', new Schema({})); ``` @@ -87,8 +87,8 @@ no longer supports several function signatures for `mongoose.connect()` that worked in Mongoose 4.x if the `useMongoClient` option was off. Below are some examples of `mongoose.connect()` calls that do **not** work in Mongoose 5.x. -* `mongoose.connect('localhost', 27017);` -* `mongoose.connect('localhost', 'mydb', 27017);` +* `mongoose.connect('127.0.0.1', 27017);` +* `mongoose.connect('127.0.0.1', 'mydb', 27017);` * `mongoose.connect('mongodb://host1:27017,mongodb://host2:27017');` In Mongoose 5.x, the first parameter to `mongoose.connect()` and `mongoose.createConnection()`, if specified, **must** be a [MongoDB connection string](https://docs.mongodb.com/manual/reference/connection-string/). The diff --git a/docs/migrating_to_6.md b/docs/migrating_to_6.md index c964705dd86..5b9245d856c 100644 --- a/docs/migrating_to_6.md +++ b/docs/migrating_to_6.md @@ -90,7 +90,7 @@ res.deletedCount; // Number of documents that were deleted. Replaces `res.n` // No longer necessary: mongoose.set('useFindAndModify', false); -await mongoose.connect('mongodb://localhost:27017/test', { +await mongoose.connect('mongodb://127.0.0.1:27017/test', { useNewUrlParser: true, // <-- no longer necessary useUnifiedTopology: true // <-- no longer necessary }); diff --git a/docs/models.md b/docs/models.md index 8f9cc391822..d296684e0ef 100644 --- a/docs/models.md +++ b/docs/models.md @@ -64,13 +64,13 @@ uses is open. Every model has an associated connection. When you use `mongoose.model()`, your model will use the default mongoose connection. ```javascript -mongoose.connect('mongodb://localhost/gettingstarted'); +mongoose.connect('mongodb://127.0.0.1/gettingstarted'); ``` If you create a custom connection, use that connection's `model()` function instead. ```javascript -const connection = mongoose.createConnection('mongodb://localhost:27017/test'); +const connection = mongoose.createConnection('mongodb://127.0.0.1:27017/test'); const Tank = connection.model('Tank', yourSchema); ``` diff --git a/docs/populate.md b/docs/populate.md index 19e40db8bf2..05f6da8edcd 100644 --- a/docs/populate.md +++ b/docs/populate.md @@ -444,8 +444,8 @@ Let's say you have a schema representing events, and a schema representing conversations. Each event has a corresponding conversation thread. ```javascript -const db1 = mongoose.createConnection('mongodb://localhost:27000/db1'); -const db2 = mongoose.createConnection('mongodb://localhost:27001/db2'); +const db1 = mongoose.createConnection('mongodb://127.0.0.1:27000/db1'); +const db2 = mongoose.createConnection('mongodb://127.0.0.1:27001/db2'); const conversationSchema = new Schema({ numMessages: Number }); const Conversation = db2.model('Conversation', conversationSchema); diff --git a/docs/tutorials/ssl.md b/docs/tutorials/ssl.md index e6863640d9d..22aea4b2e99 100644 --- a/docs/tutorials/ssl.md +++ b/docs/tutorials/ssl.md @@ -3,10 +3,10 @@ Mongoose supports connecting to [MongoDB clusters that require SSL connections](https://docs.mongodb.com/manual/tutorial/configure-ssl/). Setting the `ssl` option to `true` in [`mongoose.connect()`](../api/mongoose.html#mongoose_Mongoose-connect) or your connection string is enough to connect to a MongoDB cluster using SSL: ```javascript -mongoose.connect('mongodb://localhost:27017/test', { ssl: true }); +mongoose.connect('mongodb://127.0.0.1:27017/test', { ssl: true }); // Equivalent: -mongoose.connect('mongodb://localhost:27017/test?ssl=true'); +mongoose.connect('mongodb://127.0.0.1:27017/test?ssl=true'); ``` The `ssl` option defaults to `false` for connection strings that start with `mongodb://`. However, @@ -27,7 +27,7 @@ By default, Mongoose validates the SSL certificate against a [certificate author to `false`. ```javascript -mongoose.connect('mongodb://localhost:27017/test', { +mongoose.connect('mongodb://127.0.0.1:27017/test', { ssl: true, sslValidate: false }); @@ -49,7 +49,7 @@ server is not registered with an established certificate authority. The solution [essentially sets a list of allowed SSL certificates](https://mongodb.github.io/node-mongodb-native/2.1/tutorials/connect/ssl/). ```javascript -await mongoose.connect('mongodb://localhost:27017/test', { +await mongoose.connect('mongodb://127.0.0.1:27017/test', { ssl: true, sslValidate: true, // For example, see https://medium.com/@rajanmaharjan/secure-your-mongodb-connections-ssl-tls-92e2addb3c89 @@ -76,7 +76,7 @@ If you're using [X509 authentication](https://www.mongodb.com/docs/drivers/node/ ```javascript // Do this: const username = 'myusername'; -await mongoose.connect(`mongodb://${encodeURIComponent(username)}@localhost:27017/test`, { +await mongoose.connect(`mongodb://${encodeURIComponent(username)}@127.0.0.1:27017/test`, { ssl: true, sslValidate: true, sslCA: `${__dirname}/rootCA.pem`, @@ -84,11 +84,11 @@ await mongoose.connect(`mongodb://${encodeURIComponent(username)}@localhost:2701 }); // Not this: -await mongoose.connect(`mongodb://localhost:27017/test`, { +await mongoose.connect(`mongodb://127.0.0.1:27017/test`, { ssl: true, sslValidate: true, sslCA: `${__dirname}/rootCA.pem`, authMechanism: 'MONGODB-X509'. auth: { username } }); -``` \ No newline at end of file +``` diff --git a/docs/typescript.md b/docs/typescript.md index 1f96873c7af..6a8eba3024f 100644 --- a/docs/typescript.md +++ b/docs/typescript.md @@ -37,7 +37,7 @@ run().catch(err => console.log(err)); async function run() { // 4. Connect to MongoDB - await connect('mongodb://localhost:27017/test'); + await connect('mongodb://127.0.0.1:27017/test'); const user = new User({ name: 'Bill', diff --git a/docs/typescript/query-helpers.md b/docs/typescript/query-helpers.md index de6bb1daf60..1afb2f8af0b 100644 --- a/docs/typescript/query-helpers.md +++ b/docs/typescript/query-helpers.md @@ -69,7 +69,7 @@ const ProjectModel = model('Project', schema); run().catch(err => console.log(err)); async function run(): Promise { - await connect('mongodb://localhost:27017/test'); + await connect('mongodb://127.0.0.1:27017/test'); // Equivalent to `ProjectModel.find({ stars: { $gt: 1000 }, name: 'mongoose' })` await ProjectModel.find().where('stars').gt(1000).byName('mongoose'); @@ -99,4 +99,4 @@ const ProjectModel = model('Project', ProjectSchema); // Equivalent to `ProjectModel.find({ stars: { $gt: 1000 }, name: 'mongoose' })` await ProjectModel.find().where('stars').gt(1000).byName('mongoose'); -``` \ No newline at end of file +``` diff --git a/examples/aggregate/aggregate.js b/examples/aggregate/aggregate.js index 59b315425f6..8a97e1e74d9 100644 --- a/examples/aggregate/aggregate.js +++ b/examples/aggregate/aggregate.js @@ -51,7 +51,7 @@ const data = [ ]; -mongoose.connect('mongodb://localhost/persons', function(err) { +mongoose.connect('mongodb://127.0.0.1/persons', function(err) { if (err) throw err; // create all of the dummy people diff --git a/examples/doc-methods.js b/examples/doc-methods.js index 52f4f6f2e49..d6b34599998 100644 --- a/examples/doc-methods.js +++ b/examples/doc-methods.js @@ -36,12 +36,12 @@ CharacterSchema.methods.attack = function() { const Character = mongoose.model('Character', CharacterSchema); /** - * Connect to the database on localhost with + * Connect to the database on 127.0.0.1 with * the default port (27017) */ const dbname = 'mongoose-example-doc-methods-' + ((Math.random() * 10000) | 0); -const uri = 'mongodb://localhost/' + dbname; +const uri = 'mongodb://127.0.0.1/' + dbname; console.log('connecting to %s', uri); diff --git a/examples/express/connection-sharing/README.md b/examples/express/connection-sharing/README.md index fc709a3ab70..9f732f0965e 100644 --- a/examples/express/connection-sharing/README.md +++ b/examples/express/connection-sharing/README.md @@ -3,4 +3,4 @@ To run: - Execute `npm install` from this directory - Execute `node app.js` -- Navigate to `localhost:8000` +- Navigate to `127.0.0.1:8000` diff --git a/examples/express/connection-sharing/app.js b/examples/express/connection-sharing/app.js index ddae7bd0be2..8c0efae338e 100644 --- a/examples/express/connection-sharing/app.js +++ b/examples/express/connection-sharing/app.js @@ -2,7 +2,7 @@ const express = require('express'); const mongoose = require('../../../lib'); -const uri = 'mongodb://localhost/mongoose-shared-connection'; +const uri = 'mongodb://127.0.0.1/mongoose-shared-connection'; global.db = mongoose.createConnection(uri); const routes = require('./routes'); @@ -12,4 +12,4 @@ app.get('/', routes.home); app.get('/insert', routes.insert); app.get('/name', routes.modelName); -app.listen(8000, () => console.log('listening on http://localhost:8000')); +app.listen(8000, () => console.log('listening on http://127.0.0.1:8000')); diff --git a/examples/geospatial/geoJSONexample.js b/examples/geospatial/geoJSONexample.js index 6c7507c0876..5f1fd2dbb87 100644 --- a/examples/geospatial/geoJSONexample.js +++ b/examples/geospatial/geoJSONexample.js @@ -21,7 +21,7 @@ const data = [ ]; -mongoose.connect('mongodb://localhost/locations', function(err) { +mongoose.connect('mongodb://127.0.0.1/locations', function(err) { if (err) { throw err; } diff --git a/examples/geospatial/geospatial.js b/examples/geospatial/geospatial.js index 4b5b8705b08..396394b91a8 100644 --- a/examples/geospatial/geospatial.js +++ b/examples/geospatial/geospatial.js @@ -55,7 +55,7 @@ const data = [ ]; -mongoose.connect('mongodb://localhost/persons', function(err) { +mongoose.connect('mongodb://127.0.0.1/persons', function(err) { if (err) { throw err; } diff --git a/examples/globalschemas/gs_example.js b/examples/globalschemas/gs_example.js index da1416f0d29..3b9a74f9dd5 100644 --- a/examples/globalschemas/gs_example.js +++ b/examples/globalschemas/gs_example.js @@ -10,7 +10,7 @@ const Person = mongoose.model('Person'); // connect to a server to do a quick write / read example -mongoose.connect('mongodb://localhost/persons', function(err) { +mongoose.connect('mongodb://127.0.0.1/persons', function(err) { if (err) { throw err; } diff --git a/examples/lean/lean.js b/examples/lean/lean.js index f817b1d4f86..95759a40a6b 100644 --- a/examples/lean/lean.js +++ b/examples/lean/lean.js @@ -51,7 +51,7 @@ const data = [ ]; -mongoose.connect('mongodb://localhost/persons', function(err) { +mongoose.connect('mongodb://127.0.0.1/persons', function(err) { if (err) throw err; // create all of the dummy people diff --git a/examples/mapreduce/mapreduce.js b/examples/mapreduce/mapreduce.js index 24c21e42eca..23bf8f4a60e 100644 --- a/examples/mapreduce/mapreduce.js +++ b/examples/mapreduce/mapreduce.js @@ -45,7 +45,7 @@ const data = [ ]; -mongoose.connect('mongodb://localhost/persons', function(err) { +mongoose.connect('mongodb://127.0.0.1/persons', function(err) { if (err) throw err; // create all of the dummy people diff --git a/examples/population/population-across-three-collections.js b/examples/population/population-across-three-collections.js index 61ab4275c64..e3ef031d9b9 100644 --- a/examples/population/population-across-three-collections.js +++ b/examples/population/population-across-three-collections.js @@ -10,7 +10,7 @@ const ObjectId = mongoose.Types.ObjectId; */ const dbname = 'testing_populateAdInfinitum_' + require('../../lib/utils').random(); -mongoose.connect('localhost', dbname); +mongoose.connect('127.0.0.1', dbname); mongoose.connection.on('error', function() { console.error('connection error', arguments); }); diff --git a/examples/population/population-basic.js b/examples/population/population-basic.js index 9be961713b9..a6c7ea88c7f 100644 --- a/examples/population/population-basic.js +++ b/examples/population/population-basic.js @@ -32,11 +32,11 @@ const gameSchema = Schema({ const Game = mongoose.model('Game', gameSchema); /** - * Connect to the console database on localhost with + * Connect to the console database on 127.0.0.1 with * the default port (27017) */ -mongoose.connect('mongodb://localhost/console', function(err) { +mongoose.connect('mongodb://127.0.0.1/console', function(err) { // if we failed to connect, abort if (err) throw err; diff --git a/examples/population/population-of-existing-doc.js b/examples/population/population-of-existing-doc.js index d008f4f313c..4223f3ae9e4 100644 --- a/examples/population/population-of-existing-doc.js +++ b/examples/population/population-of-existing-doc.js @@ -32,11 +32,11 @@ const gameSchema = Schema({ const Game = mongoose.model('Game', gameSchema); /** - * Connect to the console database on localhost with + * Connect to the console database on 127.0.0.1 with * the default port (27017) */ -mongoose.connect('mongodb://localhost/console', function(err) { +mongoose.connect('mongodb://127.0.0.1/console', function(err) { // if we failed to connect, abort if (err) throw err; diff --git a/examples/population/population-of-multiple-existing-docs.js b/examples/population/population-of-multiple-existing-docs.js index f070d6cccd8..310d0a40c05 100644 --- a/examples/population/population-of-multiple-existing-docs.js +++ b/examples/population/population-of-multiple-existing-docs.js @@ -32,11 +32,11 @@ const gameSchema = Schema({ const Game = mongoose.model('Game', gameSchema); /** - * Connect to the console database on localhost with + * Connect to the console database on 127.0.0.1 with * the default port (27017) */ -mongoose.connect('mongodb://localhost/console', function(err) { +mongoose.connect('mongodb://127.0.0.1/console', function(err) { // if we failed to connect, abort if (err) throw err; diff --git a/examples/population/population-options.js b/examples/population/population-options.js index 8bd18fa97a7..2e75556ddd4 100644 --- a/examples/population/population-options.js +++ b/examples/population/population-options.js @@ -32,11 +32,11 @@ const gameSchema = Schema({ const Game = mongoose.model('Game', gameSchema); /** - * Connect to the console database on localhost with + * Connect to the console database on 127.0.0.1 with * the default port (27017) */ -mongoose.connect('mongodb://localhost/console', function(err) { +mongoose.connect('mongodb://127.0.0.1/console', function(err) { // if we failed to connect, abort if (err) throw err; diff --git a/examples/population/population-plain-objects.js b/examples/population/population-plain-objects.js index e0fb91cc6fc..ed5abe03d1e 100644 --- a/examples/population/population-plain-objects.js +++ b/examples/population/population-plain-objects.js @@ -32,11 +32,11 @@ const gameSchema = Schema({ const Game = mongoose.model('Game', gameSchema); /** - * Connect to the console database on localhost with + * Connect to the console database on 127.0.0.1 with * the default port (27017) */ -mongoose.connect('mongodb://localhost/console', function(err) { +mongoose.connect('mongodb://127.0.0.1/console', function(err) { // if we failed to connect, abort if (err) throw err; diff --git a/examples/promises/promise.js b/examples/promises/promise.js index 45f474296a6..a0660c9a1a0 100644 --- a/examples/promises/promise.js +++ b/examples/promises/promise.js @@ -40,7 +40,7 @@ const data = [ ]; -mongoose.connect('mongodb://localhost/persons', function(err) { +mongoose.connect('mongodb://127.0.0.1/persons', function(err) { if (err) { throw err; } diff --git a/examples/querybuilder/querybuilder.js b/examples/querybuilder/querybuilder.js index 5561f9157dc..a05059c001c 100644 --- a/examples/querybuilder/querybuilder.js +++ b/examples/querybuilder/querybuilder.js @@ -41,7 +41,7 @@ const data = [ ]; -mongoose.connect('mongodb://localhost/persons', function(err) { +mongoose.connect('mongodb://127.0.0.1/persons', function(err) { if (err) throw err; // create all of the dummy people diff --git a/examples/redis-todo/db/index.js b/examples/redis-todo/db/index.js index 3305fe8a8d3..c12d30bd323 100644 --- a/examples/redis-todo/db/index.js +++ b/examples/redis-todo/db/index.js @@ -2,4 +2,4 @@ const mongoose = require('mongoose'); -mongoose.connect('mongodb://localhost/redis-todo'); +mongoose.connect('mongodb://127.0.0.1/redis-todo'); diff --git a/examples/replicasets/replica-sets.js b/examples/replicasets/replica-sets.js index 74217bf113e..cb9b91df7e8 100644 --- a/examples/replicasets/replica-sets.js +++ b/examples/replicasets/replica-sets.js @@ -46,7 +46,7 @@ const data = [ const opts = { replSet: { rs_name: 'rs0' } }; -mongoose.connect('mongodb://localhost:27018/persons,localhost:27019,localhost:27020', opts, function(err) { +mongoose.connect('mongodb://127.0.0.1:27018/persons,127.0.0.1:27019,127.0.0.1:27020', opts, function(err) { if (err) throw err; // create all of the dummy people diff --git a/examples/statics/statics.js b/examples/statics/statics.js index 460b194fa86..b1e5aabb867 100644 --- a/examples/statics/statics.js +++ b/examples/statics/statics.js @@ -12,7 +12,7 @@ const Person = mongoose.model('Person'); run().catch(console.error); async function run() { - await mongoose.connect('mongodb://localhost/persons'); + await mongoose.connect('mongodb://127.0.0.1/persons'); const bill = await Person.create({ name: 'bill', age: 25, diff --git a/index.pug b/index.pug index 7cac37cff09..c0788cbdc93 100644 --- a/index.pug +++ b/index.pug @@ -121,7 +121,7 @@ html(lang='en') :markdown ```javascript const mongoose = require('mongoose'); - mongoose.connect('mongodb://localhost:27017/test'); + mongoose.connect('mongodb://127.0.0.1:27017/test'); const Cat = mongoose.model('Cat', { name: String }); diff --git a/lib/connection.js b/lib/connection.js index 137f927d68e..9339f138a05 100644 --- a/lib/connection.js +++ b/lib/connection.js @@ -196,7 +196,7 @@ Connection.prototype.collections; * * #### Example: * - * mongoose.createConnection('mongodb://localhost:27017/mydb').name; // "mydb" + * mongoose.createConnection('mongodb://127.0.0.1:27017/mydb').name; // "mydb" * * @property name * @memberOf Connection @@ -253,7 +253,7 @@ Connection.prototype.id; * * #### Example: * - * const db = mongoose.createConnection('mongodb://localhost:27017/mydb'); + * const db = mongoose.createConnection('mongodb://127.0.0.1:27017/mydb'); * db.plugin(() => console.log('Applied')); * db.plugins.length; // 1 * @@ -277,7 +277,7 @@ Object.defineProperty(Connection.prototype, 'plugins', { * * #### Example: * - * mongoose.createConnection('mongodb://localhost:27017/mydb').host; // "localhost" + * mongoose.createConnection('mongodb://127.0.0.1:27017/mydb').host; // "127.0.0.1" * * @property host * @memberOf Connection @@ -297,7 +297,7 @@ Object.defineProperty(Connection.prototype, 'host', { * * #### Example: * - * mongoose.createConnection('mongodb://localhost:27017/mydb').port; // 27017 + * mongoose.createConnection('mongodb://127.0.0.1:27017/mydb').port; // 27017 * * @property port * @memberOf Connection @@ -316,7 +316,7 @@ Object.defineProperty(Connection.prototype, 'port', { * * #### Example: * - * mongoose.createConnection('mongodb://val:psw@localhost:27017/mydb').user; // "val" + * mongoose.createConnection('mongodb://val:psw@127.0.0.1:27017/mydb').user; // "val" * * @property user * @memberOf Connection @@ -335,7 +335,7 @@ Object.defineProperty(Connection.prototype, 'user', { * * #### Example: * - * mongoose.createConnection('mongodb://val:psw@localhost:27017/mydb').pass; // "psw" + * mongoose.createConnection('mongodb://val:psw@127.0.0.1:27017/mydb').pass; // "psw" * * @property pass * @memberOf Connection @@ -539,7 +539,7 @@ Connection.prototype.dropCollection = _wrapConnHelper(function dropCollection(co * * #### Example: * - * const conn = mongoose.createConnection('mongodb://localhost:27017/mydb'); + * const conn = mongoose.createConnection('mongodb://127.0.0.1:27017/mydb'); * // Deletes the entire 'mydb' database * await conn.dropDatabase(); * @@ -1109,7 +1109,7 @@ Connection.prototype.collection = function(name, options) { * * #### Example: * - * const db = mongoose.createConnection('mongodb://localhost:27017/mydb'); + * const db = mongoose.createConnection('mongodb://127.0.0.1:27017/mydb'); * db.plugin(() => console.log('Applied')); * db.plugins.length; // 1 * @@ -1367,7 +1367,7 @@ Connection.prototype.watch = function(pipeline, options) { * * #### Example: * - * const conn = await mongoose.createConnection('mongodb://localhost:27017/test'). + * const conn = await mongoose.createConnection('mongodb://127.0.0.1:27017/test'). * asPromise(); * conn.readyState; // 1, means Mongoose is connected * @@ -1440,7 +1440,7 @@ Connection.prototype.optionsProvideAuthenticationData = function(options) { * * #### Example: * - * const conn = await mongoose.createConnection('mongodb://localhost:27017/test'). + * const conn = await mongoose.createConnection('mongodb://127.0.0.1:27017/test'). * asPromise(); * * conn.getClient(); // MongoClient { ... } @@ -1460,7 +1460,7 @@ Connection.prototype.getClient = function getClient() { * * #### Example: * - * const client = await mongodb.MongoClient.connect('mongodb://localhost:27017/test'); + * const client = await mongodb.MongoClient.connect('mongodb://127.0.0.1:27017/test'); * * const conn = mongoose.createConnection().setClient(client); * @@ -1538,7 +1538,7 @@ Connection.prototype.syncIndexes = async function syncIndexes(options = {}) { * #### Example: * * // Connect to `initialdb` first - * const conn = await mongoose.createConnection('mongodb://localhost:27017/initialdb').asPromise(); + * const conn = await mongoose.createConnection('mongodb://127.0.0.1:27017/initialdb').asPromise(); * * // Creates an un-cached connection to `mydb` * const db = conn.useDb('mydb'); diff --git a/lib/index.js b/lib/index.js index ec2a5d733b1..5e13901b40d 100644 --- a/lib/index.js +++ b/lib/index.js @@ -309,22 +309,22 @@ Mongoose.prototype.get = Mongoose.prototype.set; * #### Example: * * // with mongodb:// URI - * db = mongoose.createConnection('mongodb://user:pass@localhost:port/database'); + * db = mongoose.createConnection('mongodb://user:pass@127.0.0.1:port/database'); * * // and options * const opts = { db: { native_parser: true }} - * db = mongoose.createConnection('mongodb://user:pass@localhost:port/database', opts); + * db = mongoose.createConnection('mongodb://user:pass@127.0.0.1:port/database', opts); * * // replica sets - * db = mongoose.createConnection('mongodb://user:pass@localhost:port,anotherhost:port,yetanother:port/database'); + * db = mongoose.createConnection('mongodb://user:pass@127.0.0.1:port,anotherhost:port,yetanother:port/database'); * * // and options * const opts = { replset: { strategy: 'ping', rs_name: 'testSet' }} - * db = mongoose.createConnection('mongodb://user:pass@localhost:port,anotherhost:port,yetanother:port/database', opts); + * db = mongoose.createConnection('mongodb://user:pass@127.0.0.1:port,anotherhost:port,yetanother:port/database', opts); * * // initialize now, connect later * db = mongoose.createConnection(); - * db.openUri('localhost', 'database', port, [opts]); + * db.openUri('127.0.0.1', 'database', port, [opts]); * * @param {String} uri mongodb URI to connect to * @param {Object} [options] passed down to the [MongoDB driver's `connect()` function](https://mongodb.github.io/node-mongodb-native/4.9/interfaces/MongoClientOptions.html), except for 4 mongoose-specific options explained below. @@ -367,10 +367,10 @@ Mongoose.prototype.createConnection = function(uri, options, callback) { * * #### Example: * - * mongoose.connect('mongodb://user:pass@localhost:port/database'); + * mongoose.connect('mongodb://user:pass@127.0.0.1:port/database'); * * // replica sets - * const uri = 'mongodb://user:pass@localhost:port,anotherhost:port,yetanother:port/mydatabase'; + * const uri = 'mongodb://user:pass@127.0.0.1:port,anotherhost:port,yetanother:port/mydatabase'; * mongoose.connect(uri); * * // with options @@ -786,7 +786,7 @@ Mongoose.prototype.__defineSetter__('connection', function(v) { * mongoose.connections.length; // 1, just the default connection * mongoose.connections[0] === mongoose.connection; // true * - * mongoose.createConnection('mongodb://localhost:27017/test'); + * mongoose.createConnection('mongodb://127.0.0.1:27017/test'); * mongoose.connections.length; // 2 * * @memberOf Mongoose diff --git a/scripts/static.js b/scripts/static.js index d2218ca2a31..6f2e0a8e8c7 100644 --- a/scripts/static.js +++ b/scripts/static.js @@ -17,7 +17,7 @@ async function main() { app.use('/', express.static(website.cwd)); app.listen(port, () => { - console.log(`now listening on http://localhost:${port}`); + console.log(`now listening on http://127.0.0.1:${port}`); }); } diff --git a/test/shard.test.js b/test/shard.test.js index e3934cc776d..d8f977af149 100644 --- a/test/shard.test.js +++ b/test/shard.test.js @@ -17,7 +17,7 @@ if (!uri) { redColorEscapeCharacter, 'You\'re not testing shards!', 'Please set the MONGOOSE_SHARD_TEST_URI env variable.', - 'e.g: `mongodb://localhost:27017/database', + 'e.g: `mongodb://127.0.0.1:27017/database', 'Sharding must already be enabled on your database', colorResetEscapeCharacter ].join('\n')); diff --git a/test/types/base.test.ts b/test/types/base.test.ts index bf4aa723d92..1dfaaa2ef70 100644 --- a/test/types/base.test.ts +++ b/test/types/base.test.ts @@ -30,7 +30,7 @@ function connectionStates() { m.STATES.connected; m.ConnectionStates.connected; - m.connect('mongodb://localhost:27017/test').then(() => { + m.connect('mongodb://127.0.0.1:27017/test').then(() => { console.log('Connected!'); }); diff --git a/test/types/connect.test.ts b/test/types/connect.test.ts index 5025406f3ed..012ea7137c2 100644 --- a/test/types/connect.test.ts +++ b/test/types/connect.test.ts @@ -2,17 +2,17 @@ import mongoose, { connect } from 'mongoose'; import { expectType } from 'tsd'; // Promise -expectType>(connect('mongodb://localhost:27017/test')); -expectType>(connect('mongodb://localhost:27017/test', {})); -expectType>(connect('mongodb://localhost:27017/test', { bufferCommands: true })); +expectType>(connect('mongodb://127.0.0.1:27017/test')); +expectType>(connect('mongodb://127.0.0.1:27017/test', {})); +expectType>(connect('mongodb://127.0.0.1:27017/test', { bufferCommands: true })); // Callback -expectType(connect('mongodb://localhost:27017/test', (err: Error | null) => { +expectType(connect('mongodb://127.0.0.1:27017/test', (err: Error | null) => { return; })); -expectType(connect('mongodb://localhost:27017/test', {}, (err: Error | null) => { +expectType(connect('mongodb://127.0.0.1:27017/test', {}, (err: Error | null) => { return; })); -expectType(connect('mongodb://localhost:27017/test', { bufferCommands: true }, (err: Error | null) => { +expectType(connect('mongodb://127.0.0.1:27017/test', { bufferCommands: true }, (err: Error | null) => { return; })); diff --git a/test/types/connection.test.ts b/test/types/connection.test.ts index 28c941c8786..0bd9e1636e0 100644 --- a/test/types/connection.test.ts +++ b/test/types/connection.test.ts @@ -4,18 +4,18 @@ import { expectAssignable, expectError, expectType } from 'tsd'; import { AutoTypedSchemaType, autoTypedSchema } from './schema.test'; expectType(createConnection()); -expectType(createConnection('mongodb://localhost:27017/test')); -expectType(createConnection('mongodb://localhost:27017/test', { appName: 'mongoose' })); -expectType(createConnection('mongodb://localhost:27017/test', { appName: 'mongoose' }, (err, res) => (expectType(res)))); +expectType(createConnection('mongodb://127.0.0.1:27017/test')); +expectType(createConnection('mongodb://127.0.0.1:27017/test', { appName: 'mongoose' })); +expectType(createConnection('mongodb://127.0.0.1:27017/test', { appName: 'mongoose' }, (err, res) => (expectType(res)))); const conn = createConnection(); expectAssignable>(conn.model('Test', new Schema<{ name: string }>({ name: { type: String } }))); expectType>(conn.model<{ name: string }>('Test', new Schema({ name: { type: String } }))); -expectType>(conn.openUri('mongodb://localhost:27017/test')); -expectType>(conn.openUri('mongodb://localhost:27017/test', { bufferCommands: true })); -expectType(conn.openUri('mongodb://localhost:27017/test', { bufferCommands: true }, (err, value) => { +expectType>(conn.openUri('mongodb://127.0.0.1:27017/test')); +expectType>(conn.openUri('mongodb://127.0.0.1:27017/test', { bufferCommands: true })); +expectType(conn.openUri('mongodb://127.0.0.1:27017/test', { bufferCommands: true }, (err, value) => { expectType(value); })); @@ -43,22 +43,22 @@ expectType(conn.deleteModel(/.+/)); expectType>(conn.modelNames()); -expectType>(createConnection('mongodb://localhost:27017/test').close()); -expectType>(createConnection('mongodb://localhost:27017/test').close(true)); -expectType(createConnection('mongodb://localhost:27017/test').close(() => { +expectType>(createConnection('mongodb://127.0.0.1:27017/test').close()); +expectType>(createConnection('mongodb://127.0.0.1:27017/test').close(true)); +expectType(createConnection('mongodb://127.0.0.1:27017/test').close(() => { // do nothing. })); -expectType(createConnection('mongodb://localhost:27017/test').close(true, () => { +expectType(createConnection('mongodb://127.0.0.1:27017/test').close(true, () => { // do nothing. })); -expectType(createConnection('mongodb://localhost:27017/test').close(false, () => { +expectType(createConnection('mongodb://127.0.0.1:27017/test').close(false, () => { // do nothing. })); expectType(conn.db); expectType(conn.getClient()); -expectType(conn.setClient(new mongodb.MongoClient('mongodb://localhost:27017/test'))); +expectType(conn.setClient(new mongodb.MongoClient('mongodb://127.0.0.1:27017/test'))); expectType>(conn.transaction(async(res) => { expectType(res); diff --git a/tools/auth.js b/tools/auth.js index 2fddafaf7b2..22730c53233 100644 --- a/tools/auth.js +++ b/tools/auth.js @@ -21,11 +21,11 @@ async function run() { // Start process await server.start(); - const db = await mongodb.MongoClient.connect('mongodb://localhost:27017/admin'); + const db = await mongodb.MongoClient.connect('mongodb://127.0.0.1:27017/admin'); await db.addUser('passwordIsTaco', 'taco', { roles: ['dbOwner'] }); console.log('done'); -} \ No newline at end of file +} diff --git a/tools/sharded.js b/tools/sharded.js index 39aeed3d571..96ad95c6ced 100644 --- a/tools/sharded.js +++ b/tools/sharded.js @@ -17,18 +17,18 @@ async function run() { await topology.addShard([{ options: { - bind_ip: 'localhost', port: 31000, dbpath: '/data/db/31000', shardsvr: null + bind_ip: '127.0.0.1', port: 31000, dbpath: '/data/db/31000', shardsvr: null } }], { replSet: 'rs1' }); await topology.addConfigurationServers([{ options: { - bind_ip: 'localhost', port: 35000, dbpath: '/data/db/35000' + bind_ip: '127.0.0.1', port: 35000, dbpath: '/data/db/35000' } }], { replSet: 'rs0' }); await topology.addProxies([{ - bind_ip: 'localhost', port: 51000, configdb: 'localhost:35000' + bind_ip: '127.0.0.1', port: 51000, configdb: '127.0.0.1:35000' }], { binary: 'mongos' }); @@ -43,4 +43,4 @@ async function run() { await topology.enableSharding('test'); console.log('done'); -} \ No newline at end of file +} From 79d76ea8b3ee9638b846415fbe670fa07f76922a Mon Sep 17 00:00:00 2001 From: Daniel Diaz <39510674+IslandRhythms@users.noreply.github.com> Date: Mon, 19 Dec 2022 14:31:32 -0500 Subject: [PATCH 22/23] added tutorial to getters-setters --- docs/tutorials/getters-setters.md | 8 +++++ test/docs/getters-setters.test.js | 49 +++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/docs/tutorials/getters-setters.md b/docs/tutorials/getters-setters.md index dc94fb6a41b..31d2b3ce247 100644 --- a/docs/tutorials/getters-setters.md +++ b/docs/tutorials/getters-setters.md @@ -81,3 +81,11 @@ corresponding getter for `email`. ```javascript [require:getters/setters.*setters.*vs ES6] ``` + +## $locals + +You can use `$locals` to support internationalization for your application. + +```javascript +[require:getters/setters.*localization.*locale] +``` diff --git a/test/docs/getters-setters.test.js b/test/docs/getters-setters.test.js index 80c7d1799a9..1c5c89bb610 100644 --- a/test/docs/getters-setters.test.js +++ b/test/docs/getters-setters.test.js @@ -174,4 +174,53 @@ describe('getters/setters', function() { // acquit:ignore:end }); }); + describe('localization', function() { + it('locale', async function() { + const internationalizedStringSchema = new Schema({ + en: String, + es: String + }); + + const ingredientSchema = new Schema({ + // Instead of setting `name` to just a string, set `name` to a map + // of language codes to strings. + name: { + type: internationalizedStringSchema, + // When you access `name`, pull the document's locale + get: function(value) { + return value[this.$locals.language || 'en']; + } + } + }); + + const recipeSchema = new Schema({ + ingredients: [{ type: mongoose.ObjectId, ref: 'Ingredient' }] + }); + + const Ingredient = mongoose.model('Ingredient', ingredientSchema); + const Recipe = mongoose.model('Recipe', recipeSchema); + + // Create some sample data + const { _id } = await Ingredient.create({ + name: { + en: 'Eggs', + es: 'Huevos' + } + }); + await Recipe.create({ ingredients: [_id] }); + + // Populate with setting `$locals.language` for internationalization + const language = 'es'; + const recipes = await Recipe.find().populate({ + path: 'ingredients', + transform: function(doc) { + doc.$locals.language = language; + return doc; + } + }); + + // Gets the ingredient's name in Spanish `name.es` + assert.equal(recipes[0].ingredients[0].name, 'Huevos'); // 'Huevos' + }); + }) }); \ No newline at end of file From b50148eec5ad6f210e567bb253457a2c58648541 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Mon, 19 Dec 2022 15:32:15 -0500 Subject: [PATCH 23/23] Update getters-setters.md --- docs/tutorials/getters-setters.md | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/docs/tutorials/getters-setters.md b/docs/tutorials/getters-setters.md index 31d2b3ce247..48aebce9182 100644 --- a/docs/tutorials/getters-setters.md +++ b/docs/tutorials/getters-setters.md @@ -70,6 +70,19 @@ below. [require:getters/setters.*setters.*update skip] ``` +## Passing Parameters using `$locals` + +You can't pass parameters to your getter and setter functions like you do to normal function calls. +To configure or pass additional properties to your getters and setters, you can use the document's `$locals` property. + +The `$locals` property is the preferred place to store any program-defined data on your document without conflicting with schema-defined properties. +In your getter and setter functions, `this` is the document being accessed, so you set properties on `$locals` and then access those properties in your getters examples. +For example, the following shows how you can use `$locals` to configure the language for a custom getter that returns a string in different languages. + +```javascript +[require:getters/setters.*localization.*locale] +``` + Differences vs ES6 Getters/Setters ---------------------------------- @@ -81,11 +94,3 @@ corresponding getter for `email`. ```javascript [require:getters/setters.*setters.*vs ES6] ``` - -## $locals - -You can use `$locals` to support internationalization for your application. - -```javascript -[require:getters/setters.*localization.*locale] -```