├── CNAME
├── .npmrc
├── types
├── .gitignore
├── augmentations.d.ts
├── callback.d.ts
├── virtuals.d.ts
├── validation.d.ts
└── helpers.d.ts
├── benchmarks
├── typescript
│ └── simple
│ │ ├── .npmrc
│ │ ├── tsconfig.json
│ │ ├── package.json
│ │ └── index.ts
├── insertManySimple.js
└── createDeepNestedDocArray.js
├── lib
├── drivers
│ ├── SPEC.md
│ └── node-mongodb-native
│ │ ├── bulkWriteResult.js
│ │ └── index.js
├── helpers
│ ├── timers.js
│ ├── query
│ │ ├── validOps.js
│ │ ├── isOperator.js
│ │ ├── trusted.js
│ │ ├── sanitizeProjection.js
│ │ ├── hasDollarKeys.js
│ │ ├── handleReadPreferenceAliases.js
│ │ ├── applyGlobalOption.js
│ │ ├── sanitizeFilter.js
│ │ └── castFilterPath.js
│ ├── specialProperties.js
│ ├── populate
│ │ ├── leanPopulateMap.js
│ │ ├── skipPopulateValue.js
│ │ ├── validateRef.js
│ │ ├── removeDeselectedForeignField.js
│ │ ├── lookupLocalFields.js
│ │ └── setPopulatedVirtualValue.js
│ ├── firstKey.js
│ ├── isPromise.js
│ ├── schema
│ │ ├── addAutoId.js
│ │ ├── cleanPositionalOperators.js
│ │ ├── applyBuiltinPlugins.js
│ │ ├── handleTimestampOption.js
│ │ ├── handleIdOption.js
│ │ ├── applyReadConcern.js
│ │ ├── idGetter.js
│ │ ├── getKeysInSchemaOrder.js
│ │ ├── merge.js
│ │ ├── getSubdocumentStrictValue.js
│ │ └── getPath.js
│ ├── isAsyncFunction.js
│ ├── getFunctionName.js
│ ├── once.js
│ ├── isBsonType.js
│ ├── projection
│ │ ├── isNestedProjection.js
│ │ ├── isSubpath.js
│ │ ├── isDefiningProjection.js
│ │ ├── isPathSelectedInclusive.js
│ │ ├── parseProjection.js
│ │ ├── isPathExcluded.js
│ │ ├── isExclusive.js
│ │ ├── hasIncludedChildren.js
│ │ └── isInclusive.js
│ ├── model
│ │ ├── applyStatics.js
│ │ ├── decorateBulkWriteResult.js
│ │ ├── pushNestedArrayPaths.js
│ │ └── applyStaticHooks.js
│ ├── isObject.js
│ ├── indexes
│ │ ├── isTextIndex.js
│ │ ├── applySchemaCollation.js
│ │ ├── isDefaultIdIndex.js
│ │ ├── isTimeseriesIndex.js
│ │ ├── decorateDiscriminatorIndexOptions.js
│ │ └── isIndexSpecEqual.js
│ ├── getDefaultBulkwriteResult.js
│ ├── getConstructorName.js
│ ├── topology
│ │ ├── allServersUnknown.js
│ │ ├── isSSLError.js
│ │ └── isAtlas.js
│ ├── path
│ │ ├── parentPaths.js
│ │ └── setDottedPath.js
│ ├── isPOJO.js
│ ├── error
│ │ └── combinePathErrors.js
│ ├── omitUndefined.js
│ ├── discriminator
│ │ ├── areDiscriminatorValuesEqual.js
│ │ ├── checkEmbeddedDiscriminatorKeyProjection.js
│ │ ├── getDiscriminatorByValue.js
│ │ ├── getSchemaDiscriminatorByValue.js
│ │ ├── getConstructor.js
│ │ └── applyEmbeddedDiscriminators.js
│ ├── each.js
│ ├── isSimpleValidator.js
│ ├── immediate.js
│ ├── isMongooseObject.js
│ ├── createJSONSchemaTypeDefinition.js
│ ├── minimize.js
│ ├── parallelLimit.js
│ ├── arrayDepth.js
│ ├── update
│ │ ├── updatedPathsByArrayFilter.js
│ │ ├── decorateUpdateWithVersionKey.js
│ │ ├── modifiedPaths.js
│ │ └── removeUnusedArrayFilters.js
│ ├── document
│ │ ├── handleSpreadDoc.js
│ │ ├── getDeepestSubdocumentForPath.js
│ │ └── cleanModifiedSubpaths.js
│ ├── timestamps
│ │ └── setDocumentTimestamps.js
│ ├── printJestWarning.js
│ └── symbols.js
├── options
│ ├── propertyOptions.js
│ ├── saveOptions.js
│ ├── schemaUnionOptions.js
│ ├── schemaBufferOptions.js
│ ├── populateOptions.js
│ └── schemaMapOptions.js
├── schema
│ ├── symbols.js
│ ├── operators
│ │ ├── exists.js
│ │ ├── type.js
│ │ ├── helpers.js
│ │ ├── bitwise.js
│ │ └── text.js
│ └── index.js
├── types
│ ├── array
│ │ └── isMongooseArray.js
│ ├── documentArray
│ │ └── isMongooseDocumentArray.js
│ ├── uuid.js
│ ├── double.js
│ ├── decimal128.js
│ ├── index.js
│ └── objectid.js
├── driver.js
├── plugins
│ ├── index.js
│ └── validateBeforeSave.js
├── error
│ ├── mongooseError.js
│ ├── browserMissingSchema.js
│ ├── overwriteModel.js
│ ├── createCollectionsError.js
│ ├── syncIndexes.js
│ ├── parallelSave.js
│ ├── missingSchema.js
│ ├── parallelValidate.js
│ ├── invalidSchemaOption.js
│ ├── objectExpected.js
│ ├── strictPopulate.js
│ ├── strict.js
│ ├── objectParameter.js
│ ├── version.js
│ ├── eachAsyncMultiError.js
│ ├── bulkWriteError.js
│ ├── notFound.js
│ └── divergentArray.js
├── modifiedPathsSnapshot.js
├── options.js
├── index.js
├── connectionState.js
├── cast
│ ├── objectid.js
│ ├── boolean.js
│ ├── int32.js
│ ├── number.js
│ ├── uuid.js
│ ├── decimal128.js
│ ├── string.js
│ ├── date.js
│ └── bigint.js
├── validOptions.js
└── constants.js
├── History.md
├── docs
├── images
│ ├── dk.png
│ ├── mixmax.png
│ ├── asyncawait.png
│ ├── link_64x64.png
│ ├── square_bg.png
│ ├── fortunegames.jpg
│ ├── favicon
│ │ ├── favicon.ico
│ │ ├── apple-icon.png
│ │ ├── favicon-16x16.png
│ │ ├── favicon-32x32.png
│ │ ├── favicon-96x96.png
│ │ ├── ms-icon-144x144.png
│ │ ├── ms-icon-150x150.png
│ │ ├── ms-icon-310x310.png
│ │ ├── ms-icon-70x70.png
│ │ ├── apple-icon-57x57.png
│ │ ├── apple-icon-60x60.png
│ │ ├── apple-icon-72x72.png
│ │ ├── apple-icon-76x76.png
│ │ ├── android-icon-144x144.png
│ │ ├── android-icon-192x192.png
│ │ ├── android-icon-36x36.png
│ │ ├── android-icon-48x48.png
│ │ ├── android-icon-72x72.png
│ │ ├── android-icon-96x96.png
│ │ ├── apple-icon-114x114.png
│ │ ├── apple-icon-120x120.png
│ │ ├── apple-icon-144x144.png
│ │ ├── apple-icon-152x152.png
│ │ ├── apple-icon-180x180.png
│ │ ├── apple-icon-precomposed.png
│ │ ├── browserconfig.xml
│ │ └── manifest.json
│ ├── logo-poprey-com-white-100.png
│ ├── localize-mongoose-ad-banner-2x.jpg
│ ├── tidelift.svg
│ ├── search.svg
│ └── pencil.svg
├── deprecations.md
├── source
│ ├── home.js
│ ├── typescript.js
│ ├── tutorials.js
│ └── utils.js
├── api.md
├── browser.md
├── advanced_schemas.md
├── incompatible_packages.md
├── css
│ ├── carbonads.css
│ ├── copy-code.css
│ └── inlinecpc.css
├── includes
│ └── native.pug
├── sponsors.pug
├── search.pug
├── js
│ ├── redirect-old-api.js
│ ├── navbar-search.js
│ ├── theme-toggle.js
│ └── mobile-navbar-toggle.js
├── customschematypes.md
├── tutorials
│ └── custom-casting.md
└── check-version.md
├── .github
├── codeql
│ └── codeql-config.yml
├── FUNDING.yml
├── ISSUE_TEMPLATE
│ ├── config.yml
│ ├── other.yml
│ └── feature.yml
├── dependabot.yml
├── PULL_REQUEST_TEMPLATE.md
└── workflows
│ ├── stale.yml
│ ├── publish.yml
│ ├── benchmark.yml
│ ├── tidelift-alignment.yml
│ └── tsd.yml
├── migrating_to_5.md
├── SECURITY.md
├── test
├── types
│ ├── objectid.test.ts
│ ├── esm.test.ts
│ ├── sanitizeFilter.test.ts
│ ├── connect.test.ts
│ ├── generics.test.ts
│ ├── mongo.test.ts
│ ├── collection.test.ts
│ ├── methods.test.ts
│ ├── helpers.test.ts
│ ├── Errors.test.ts
│ ├── check-types-filename.js
│ ├── utility.test.ts
│ └── queryhelpers.test.ts
├── isolated
│ └── project-has-error.toJSON.js
├── subdirs.test.js
├── esm.test.js
├── helpers
│ ├── projection.isExclusive.test.js
│ ├── projection.isInclusive.test.js
│ ├── update.applyTimestampsToUpdate.test.js
│ ├── update.removeUnusedArrayFilters.test.js
│ ├── projection.test.js
│ ├── getFunctionName.test.js
│ ├── common.test.js
│ ├── applyWriteConcern.test.js
│ ├── schema.cleanPositionalOperators.test.js
│ ├── update.applyTimestampsToChildren.test.js
│ ├── indexes.isIndexSpecEqual.js
│ ├── isAsyncFunction.test.js
│ ├── query.selectPopulatedFields.test.js
│ ├── getModelsMapForPopulate.test.js
│ ├── isObject.test.js
│ ├── get.test.js
│ └── schema.getPath.test.js
├── virtualtype.test.js
├── schemaname.test.js
├── deno.mjs
├── schema.string.test.js
├── schema.number.test.js
├── schema.boolean.test.js
├── parallelLimit.test.js
├── types.decimal128.test.js
├── schema.mixed.test.js
├── multiple-require-instance.test.js
└── types.embeddeddocument.test.js
├── lgtm.yml
├── tsconfig.json
├── scripts
├── create-tarball.js
├── tsc-diagnostics-check.js
└── static.js
├── .mocharc.yml
├── tools
├── auth.js
├── repl.js
└── sharded.js
├── .npmignore
├── release-items.md
├── LICENSE.md
└── .gitignore
/CNAME:
--------------------------------------------------------------------------------
1 | mongoosejs.com
2 |
--------------------------------------------------------------------------------
/.npmrc:
--------------------------------------------------------------------------------
1 | package-lock=false
2 |
--------------------------------------------------------------------------------
/types/.gitignore:
--------------------------------------------------------------------------------
1 | *
2 | !**/*.d.ts
3 |
--------------------------------------------------------------------------------
/benchmarks/typescript/simple/.npmrc:
--------------------------------------------------------------------------------
1 | package-lock=false
2 |
--------------------------------------------------------------------------------
/lib/drivers/SPEC.md:
--------------------------------------------------------------------------------
1 |
2 | # Driver Spec
3 |
4 | TODO
5 |
--------------------------------------------------------------------------------
/History.md:
--------------------------------------------------------------------------------
1 | This file has been renamed [CHANGELOG.md](./CHANGELOG.md)
2 |
--------------------------------------------------------------------------------
/lib/helpers/timers.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | exports.setTimeout = setTimeout;
4 |
--------------------------------------------------------------------------------
/benchmarks/typescript/simple/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "include": [
3 | "./*.ts"
4 | ]
5 | }
--------------------------------------------------------------------------------
/docs/images/dk.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/mongoose/HEAD/docs/images/dk.png
--------------------------------------------------------------------------------
/docs/images/mixmax.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/mongoose/HEAD/docs/images/mixmax.png
--------------------------------------------------------------------------------
/docs/images/asyncawait.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/mongoose/HEAD/docs/images/asyncawait.png
--------------------------------------------------------------------------------
/docs/images/link_64x64.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/mongoose/HEAD/docs/images/link_64x64.png
--------------------------------------------------------------------------------
/docs/images/square_bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/mongoose/HEAD/docs/images/square_bg.png
--------------------------------------------------------------------------------
/docs/images/fortunegames.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/mongoose/HEAD/docs/images/fortunegames.jpg
--------------------------------------------------------------------------------
/docs/deprecations.md:
--------------------------------------------------------------------------------
1 | # Deprecation Warnings
2 |
3 | There are no current deprecation warnings for Mongoose 9.x.
4 |
--------------------------------------------------------------------------------
/docs/images/favicon/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/mongoose/HEAD/docs/images/favicon/favicon.ico
--------------------------------------------------------------------------------
/.github/codeql/codeql-config.yml:
--------------------------------------------------------------------------------
1 | name: "codeql config"
2 |
3 | languages:
4 | - 'javascript'
5 | paths:
6 | - lib
7 |
--------------------------------------------------------------------------------
/docs/images/favicon/apple-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/mongoose/HEAD/docs/images/favicon/apple-icon.png
--------------------------------------------------------------------------------
/migrating_to_5.md:
--------------------------------------------------------------------------------
1 | This guide has moved to the [Mongoose docs site](https://mongoosejs.com/docs/migrating_to_5.html).
2 |
--------------------------------------------------------------------------------
/lib/helpers/query/validOps.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = require('../../constants').queryMiddlewareFunctions;
4 |
--------------------------------------------------------------------------------
/lib/helpers/specialProperties.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = new Set(['__proto__', 'constructor', 'prototype']);
4 |
--------------------------------------------------------------------------------
/docs/images/favicon/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/mongoose/HEAD/docs/images/favicon/favicon-16x16.png
--------------------------------------------------------------------------------
/docs/images/favicon/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/mongoose/HEAD/docs/images/favicon/favicon-32x32.png
--------------------------------------------------------------------------------
/docs/images/favicon/favicon-96x96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/mongoose/HEAD/docs/images/favicon/favicon-96x96.png
--------------------------------------------------------------------------------
/docs/images/favicon/ms-icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/mongoose/HEAD/docs/images/favicon/ms-icon-144x144.png
--------------------------------------------------------------------------------
/docs/images/favicon/ms-icon-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/mongoose/HEAD/docs/images/favicon/ms-icon-150x150.png
--------------------------------------------------------------------------------
/docs/images/favicon/ms-icon-310x310.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/mongoose/HEAD/docs/images/favicon/ms-icon-310x310.png
--------------------------------------------------------------------------------
/docs/images/favicon/ms-icon-70x70.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/mongoose/HEAD/docs/images/favicon/ms-icon-70x70.png
--------------------------------------------------------------------------------
/lib/helpers/populate/leanPopulateMap.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /*!
4 | * ignore
5 | */
6 |
7 | module.exports = new WeakMap();
8 |
--------------------------------------------------------------------------------
/docs/images/favicon/apple-icon-57x57.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/mongoose/HEAD/docs/images/favicon/apple-icon-57x57.png
--------------------------------------------------------------------------------
/docs/images/favicon/apple-icon-60x60.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/mongoose/HEAD/docs/images/favicon/apple-icon-60x60.png
--------------------------------------------------------------------------------
/docs/images/favicon/apple-icon-72x72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/mongoose/HEAD/docs/images/favicon/apple-icon-72x72.png
--------------------------------------------------------------------------------
/docs/images/favicon/apple-icon-76x76.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/mongoose/HEAD/docs/images/favicon/apple-icon-76x76.png
--------------------------------------------------------------------------------
/docs/images/logo-poprey-com-white-100.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/mongoose/HEAD/docs/images/logo-poprey-com-white-100.png
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 | Please follow the instructions on [Tidelift's security page](https://tidelift.com/docs/security) to report a security issue.
2 |
--------------------------------------------------------------------------------
/docs/images/favicon/android-icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/mongoose/HEAD/docs/images/favicon/android-icon-144x144.png
--------------------------------------------------------------------------------
/docs/images/favicon/android-icon-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/mongoose/HEAD/docs/images/favicon/android-icon-192x192.png
--------------------------------------------------------------------------------
/docs/images/favicon/android-icon-36x36.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/mongoose/HEAD/docs/images/favicon/android-icon-36x36.png
--------------------------------------------------------------------------------
/docs/images/favicon/android-icon-48x48.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/mongoose/HEAD/docs/images/favicon/android-icon-48x48.png
--------------------------------------------------------------------------------
/docs/images/favicon/android-icon-72x72.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/mongoose/HEAD/docs/images/favicon/android-icon-72x72.png
--------------------------------------------------------------------------------
/docs/images/favicon/android-icon-96x96.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/mongoose/HEAD/docs/images/favicon/android-icon-96x96.png
--------------------------------------------------------------------------------
/docs/images/favicon/apple-icon-114x114.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/mongoose/HEAD/docs/images/favicon/apple-icon-114x114.png
--------------------------------------------------------------------------------
/docs/images/favicon/apple-icon-120x120.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/mongoose/HEAD/docs/images/favicon/apple-icon-120x120.png
--------------------------------------------------------------------------------
/docs/images/favicon/apple-icon-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/mongoose/HEAD/docs/images/favicon/apple-icon-144x144.png
--------------------------------------------------------------------------------
/docs/images/favicon/apple-icon-152x152.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/mongoose/HEAD/docs/images/favicon/apple-icon-152x152.png
--------------------------------------------------------------------------------
/docs/images/favicon/apple-icon-180x180.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/mongoose/HEAD/docs/images/favicon/apple-icon-180x180.png
--------------------------------------------------------------------------------
/docs/images/favicon/apple-icon-precomposed.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/mongoose/HEAD/docs/images/favicon/apple-icon-precomposed.png
--------------------------------------------------------------------------------
/docs/images/localize-mongoose-ad-banner-2x.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Automattic/mongoose/HEAD/docs/images/localize-mongoose-ad-banner-2x.jpg
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: mongoosejs
4 | open_collective: mongoose
5 | tidelift: npm/mongoose
6 |
--------------------------------------------------------------------------------
/docs/source/home.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | const pkg = require('./../../package.json');
3 |
4 | module.exports = {
5 | package: pkg,
6 | title: 'ODM'
7 | };
8 |
--------------------------------------------------------------------------------
/lib/helpers/firstKey.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = function firstKey(obj) {
4 | if (obj == null) {
5 | return null;
6 | }
7 | return Object.keys(obj)[0];
8 | };
9 |
--------------------------------------------------------------------------------
/lib/options/propertyOptions.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = Object.freeze({
4 | enumerable: true,
5 | configurable: true,
6 | writable: true,
7 | value: void 0
8 | });
9 |
--------------------------------------------------------------------------------
/test/types/objectid.test.ts:
--------------------------------------------------------------------------------
1 | import { Types } from 'mongoose';
2 |
3 | const oid = new Types.ObjectId();
4 | oid.toHexString();
5 | oid._id;
6 |
7 | (new Types.ObjectId()).toHexString();
8 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/config.yml:
--------------------------------------------------------------------------------
1 | blank_issues_enabled: false
2 | documentation:
3 | - name: 📘 Documentation
4 | url: https://mongoosejs.com/docs/guide.html
5 | about: Mongoose Docs
6 |
--------------------------------------------------------------------------------
/docs/source/typescript.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | const { mapSubDoc } = require('./utils');
3 |
4 | mapSubDoc('typescript', {
5 | title: 'Mongoose:',
6 | markdown: true
7 | }, module.exports);
8 |
--------------------------------------------------------------------------------
/lib/drivers/node-mongodb-native/bulkWriteResult.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const BulkWriteResult = require('mongodb/lib/bulk/common').BulkWriteResult;
4 |
5 | module.exports = BulkWriteResult;
6 |
--------------------------------------------------------------------------------
/lib/schema/symbols.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | exports.schemaMixedSymbol = Symbol.for('mongoose:schema_mixed');
4 |
5 | exports.builtInMiddleware = Symbol.for('mongoose:built-in-middleware');
6 |
--------------------------------------------------------------------------------
/lib/types/array/isMongooseArray.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | exports.isMongooseArray = function(mongooseArray) {
4 | return Array.isArray(mongooseArray) && mongooseArray.isMongooseArray;
5 | };
6 |
--------------------------------------------------------------------------------
/lgtm.yml:
--------------------------------------------------------------------------------
1 | path_classifiers:
2 | src:
3 | - lib
4 | types:
5 | - types
6 | test:
7 | - test
8 | docs:
9 | - docs
10 | queries:
11 | - exclude: "*"
12 | - include: lib
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "strict": true,
4 | "strictNullChecks": true,
5 | "paths": {
6 | "mongoose" : ["./types/index.d.ts"]
7 | }
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/docs/source/tutorials.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | const { mapSubDoc } = require('./utils');
3 |
4 | mapSubDoc('tutorials', {
5 | title: 'Mongoose Tutorials:',
6 | acquit: true,
7 | markdown: true
8 | }, module.exports);
9 |
--------------------------------------------------------------------------------
/lib/helpers/isPromise.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | function isPromise(val) {
3 | return !!val && (typeof val === 'object' || typeof val === 'function') && typeof val.then === 'function';
4 | }
5 |
6 | module.exports = isPromise;
7 |
--------------------------------------------------------------------------------
/lib/helpers/schema/addAutoId.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = function addAutoId(schema) {
4 | const _obj = { _id: { auto: true } };
5 | _obj._id[schema.options.typeKey] = 'ObjectId';
6 | schema.add(_obj);
7 | };
8 |
--------------------------------------------------------------------------------
/docs/api.md:
--------------------------------------------------------------------------------
1 | # Redirecting
2 |
3 |
4 |
5 | Redirecting to proper API page, please wait
6 |
7 |
8 |
--------------------------------------------------------------------------------
/scripts/create-tarball.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const { execSync } = require('child_process');
4 | const { name, version } = require('../package.json');
5 |
6 | execSync('npm pack');
7 | execSync(`mv ${name}-${version}.tgz ${name}.tgz`);
8 |
--------------------------------------------------------------------------------
/benchmarks/typescript/simple/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": {
3 | "mongoose": "file:../../../mongoose.tgz",
4 | "typescript": "5.8.x"
5 | },
6 | "scripts": {
7 | "benchmark": "tsc --extendedDiagnostics"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/lib/driver.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /*!
4 | * ignore
5 | */
6 |
7 | let driver = null;
8 |
9 | module.exports.get = function() {
10 | return driver;
11 | };
12 |
13 | module.exports.set = function(v) {
14 | driver = v;
15 | };
16 |
--------------------------------------------------------------------------------
/lib/helpers/isAsyncFunction.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = function isAsyncFunction(v) {
4 | return (
5 | typeof v === 'function' &&
6 | v.constructor &&
7 | v.constructor.name === 'AsyncFunction'
8 | );
9 | };
10 |
--------------------------------------------------------------------------------
/lib/types/documentArray/isMongooseDocumentArray.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | exports.isMongooseDocumentArray = function(mongooseDocumentArray) {
4 | return Array.isArray(mongooseDocumentArray) && mongooseDocumentArray.isMongooseDocumentArray;
5 | };
6 |
--------------------------------------------------------------------------------
/.mocharc.yml:
--------------------------------------------------------------------------------
1 | reporter: spec # better to identify failing / slow tests than "dot"
2 | ui: bdd # explicitly setting, even though it is mocha default
3 | require:
4 | - test/mocha-fixtures.js
5 | extension:
6 | - test.js
7 | watch-files:
8 | - test/**/*.js
9 |
--------------------------------------------------------------------------------
/lib/helpers/getFunctionName.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const functionNameRE = /^function\s*([^\s(]+)/;
4 |
5 | module.exports = function(fn) {
6 | return (
7 | fn.name ||
8 | (fn.toString().trim().match(functionNameRE) || [])[1]
9 | );
10 | };
11 |
--------------------------------------------------------------------------------
/lib/plugins/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | exports.saveSubdocs = require('./saveSubdocs');
4 | exports.sharding = require('./sharding');
5 | exports.trackTransaction = require('./trackTransaction');
6 | exports.validateBeforeSave = require('./validateBeforeSave');
7 |
--------------------------------------------------------------------------------
/lib/types/uuid.js:
--------------------------------------------------------------------------------
1 | /**
2 | * UUID type constructor
3 | *
4 | * #### Example:
5 | *
6 | * const id = new mongoose.Types.UUID();
7 | *
8 | * @constructor UUID
9 | */
10 |
11 | 'use strict';
12 |
13 | module.exports = require('mongodb/lib/bson').UUID;
14 |
--------------------------------------------------------------------------------
/test/isolated/project-has-error.toJSON.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | Object.defineProperty(Error.prototype, 'toJSON', {
3 | enumerable: false,
4 | configurable: false,
5 | writable: false,
6 | value: () => ({ from: 'Error' })
7 | });
8 |
9 | require('../../');
10 |
--------------------------------------------------------------------------------
/lib/helpers/once.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = function once(fn) {
4 | let called = false;
5 | return function() {
6 | if (called) {
7 | return;
8 | }
9 | called = true;
10 | return fn.apply(null, arguments);
11 | };
12 | };
13 |
--------------------------------------------------------------------------------
/lib/error/mongooseError.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /*!
4 | * ignore
5 | */
6 |
7 | class MongooseError extends Error { }
8 |
9 | Object.defineProperty(MongooseError.prototype, 'name', {
10 | value: 'MongooseError'
11 | });
12 |
13 | module.exports = MongooseError;
14 |
--------------------------------------------------------------------------------
/lib/helpers/populate/skipPopulateValue.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = function SkipPopulateValue(val) {
4 | if (!(this instanceof SkipPopulateValue)) {
5 | return new SkipPopulateValue(val);
6 | }
7 |
8 | this.val = val;
9 | return this;
10 | };
11 |
--------------------------------------------------------------------------------
/lib/helpers/query/isOperator.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const specialKeys = new Set([
4 | '$ref',
5 | '$id',
6 | '$db'
7 | ]);
8 |
9 | module.exports = function isOperator(path) {
10 | return (
11 | path[0] === '$' &&
12 | !specialKeys.has(path)
13 | );
14 | };
15 |
--------------------------------------------------------------------------------
/lib/types/double.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Double type constructor
3 | *
4 | * #### Example:
5 | *
6 | * const pi = new mongoose.Types.Double(3.1415);
7 | *
8 | * @constructor Double
9 | */
10 |
11 | 'use strict';
12 |
13 | module.exports = require('mongodb/lib/bson').Double;
14 |
--------------------------------------------------------------------------------
/lib/schema/operators/exists.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const castBoolean = require('../../cast/boolean');
4 |
5 | /*!
6 | * ignore
7 | */
8 |
9 | module.exports = function(val) {
10 | const path = this != null ? this.path : null;
11 | return castBoolean(val, path);
12 | };
13 |
--------------------------------------------------------------------------------
/test/types/esm.test.ts:
--------------------------------------------------------------------------------
1 | import type * as mongoose from 'mongoose';
2 | import mongooseESM from 'mongoose';
3 | import * as mongooseDefault from 'mongoose';
4 | import { expectType } from 'tsd';
5 |
6 | expectType(mongooseESM);
7 | expectType(mongooseDefault);
8 |
--------------------------------------------------------------------------------
/test/types/sanitizeFilter.test.ts:
--------------------------------------------------------------------------------
1 | import { QueryFilter, sanitizeFilter } from 'mongoose';
2 | import { expectType } from 'tsd';
3 |
4 | const data = { username: 'val', pwd: { $ne: null } };
5 | type Data = typeof data;
6 |
7 | expectType>(sanitizeFilter(data));
8 |
--------------------------------------------------------------------------------
/lib/modifiedPathsSnapshot.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = class ModifiedPathsSnapshot {
4 | constructor(subdocSnapshot, activePaths, version) {
5 | this.subdocSnapshot = subdocSnapshot;
6 | this.activePaths = activePaths;
7 | this.version = version;
8 | }
9 | };
10 |
--------------------------------------------------------------------------------
/lib/helpers/isBsonType.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * Get the bson type, if it exists
5 | * @api private
6 | */
7 |
8 | function isBsonType(obj, typename) {
9 | return (
10 | obj != null &&
11 | obj._bsontype === typename
12 | );
13 | }
14 |
15 | module.exports = isBsonType;
16 |
--------------------------------------------------------------------------------
/lib/helpers/projection/isNestedProjection.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = function isNestedProjection(val) {
4 | if (val == null || typeof val !== 'object') {
5 | return false;
6 | }
7 | return val.$slice == null && val.$elemMatch == null && val.$meta == null && val.$ == null;
8 | };
9 |
--------------------------------------------------------------------------------
/lib/types/decimal128.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Decimal128 type constructor
3 | *
4 | * #### Example:
5 | *
6 | * const id = new mongoose.Types.Decimal128('3.1415');
7 | *
8 | * @constructor Decimal128
9 | */
10 |
11 | 'use strict';
12 |
13 | module.exports = require('mongodb/lib/bson').Decimal128;
14 |
--------------------------------------------------------------------------------
/docs/images/favicon/browserconfig.xml:
--------------------------------------------------------------------------------
1 |
2 | #ffffff
--------------------------------------------------------------------------------
/types/augmentations.d.ts:
--------------------------------------------------------------------------------
1 | // this import is required so that types get merged instead of completely overwritten
2 | import 'bson';
3 |
4 | declare module 'bson' {
5 | interface ObjectId {
6 | /** Mongoose automatically adds a conveniency "_id" getter on the base ObjectId class */
7 | _id: this;
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/types/callback.d.ts:
--------------------------------------------------------------------------------
1 | declare module 'mongoose' {
2 | type CallbackError = NativeError | null;
3 |
4 | type Callback = (error: CallbackError, result: T) => void;
5 |
6 | type CallbackWithoutResult = (error: CallbackError) => void;
7 | type CallbackWithoutResultAndOptionalError = (error?: CallbackError) => void;
8 | }
9 |
--------------------------------------------------------------------------------
/lib/drivers/node-mongodb-native/index.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Module exports.
3 | */
4 |
5 | 'use strict';
6 |
7 | exports.BulkWriteResult = require('./bulkWriteResult');
8 | exports.Collection = require('./collection');
9 | exports.Connection = require('./connection');
10 | exports.ClientEncryption = require('mongodb').ClientEncryption;
11 |
--------------------------------------------------------------------------------
/docs/browser.md:
--------------------------------------------------------------------------------
1 | # Mongoose in the Browser
2 |
3 | As of Mongoose 9, [Mongoose's browser build is now in the `@mongoosejs/browser` npm package](https://github.com/mongoosejs/mongoose-browser).
4 | The documentation has been moved to the [`@mongoosejs/browser` README](https://github.com/mongoosejs/mongoose-browser?tab=readme-ov-file#mongoosejsbrowser).
5 |
--------------------------------------------------------------------------------
/lib/helpers/model/applyStatics.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * Register statics for this model
5 | * @param {Model} model
6 | * @param {Schema} schema
7 | * @api private
8 | */
9 | module.exports = function applyStatics(model, schema) {
10 | for (const i in schema.statics) {
11 | model[i] = schema.statics[i];
12 | }
13 | };
14 |
--------------------------------------------------------------------------------
/lib/helpers/query/trusted.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const trustedSymbol = Symbol('mongoose#trustedSymbol');
4 |
5 | exports.trustedSymbol = trustedSymbol;
6 |
7 | exports.trusted = function trusted(obj) {
8 | if (obj == null || typeof obj !== 'object') {
9 | return obj;
10 | }
11 | obj[trustedSymbol] = true;
12 | return obj;
13 | };
14 |
--------------------------------------------------------------------------------
/test/subdirs.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const fs = require('fs');
4 |
5 | let files = fs.readdirSync(`${__dirname}/docs`);
6 |
7 | for (const file of files) {
8 | require(`./docs/${file}`);
9 | }
10 |
11 | files = fs.readdirSync(`${__dirname}/helpers`);
12 |
13 | for (const file of files) {
14 | require(`./helpers/${file}`);
15 | }
16 |
--------------------------------------------------------------------------------
/lib/options/saveOptions.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const clone = require('../helpers/clone');
4 |
5 | class SaveOptions {
6 | constructor(obj) {
7 | if (obj == null) {
8 | return;
9 | }
10 | Object.assign(this, clone(obj));
11 | }
12 | }
13 |
14 | SaveOptions.prototype.__subdocs = null;
15 |
16 | module.exports = SaveOptions;
17 |
--------------------------------------------------------------------------------
/lib/helpers/model/decorateBulkWriteResult.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = function decorateBulkWriteResult(resultOrError, validationErrors, results) {
4 | resultOrError.mongoose = resultOrError.mongoose || {};
5 | resultOrError.mongoose.validationErrors = validationErrors;
6 | resultOrError.mongoose.results = results;
7 | return resultOrError;
8 | };
9 |
--------------------------------------------------------------------------------
/lib/options.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /*!
4 | * ignore
5 | */
6 |
7 | exports.internalToObjectOptions = {
8 | transform: false,
9 | virtuals: false,
10 | getters: false,
11 | _skipDepopulateTopLevel: true,
12 | depopulate: true,
13 | flattenDecimals: false,
14 | useProjection: false,
15 | versionKey: true,
16 | flattenObjectIds: false
17 | };
18 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | version: 2
2 | updates:
3 | - package-ecosystem: npm
4 | directory: "/"
5 | schedule:
6 | interval: "monthly"
7 | open-pull-requests-limit: 100
8 | target-branch: master
9 | - package-ecosystem: github-actions
10 | directory: "/"
11 | schedule:
12 | interval: "monthly"
13 | open-pull-requests-limit: 100
14 | target-branch: master
15 |
--------------------------------------------------------------------------------
/lib/helpers/projection/isSubpath.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * Determines if `path2` is a subpath of or equal to `path1`
5 | *
6 | * @param {string} path1
7 | * @param {string} path2
8 | * @return {Boolean}
9 | * @api private
10 | */
11 |
12 | module.exports = function isSubpath(path1, path2) {
13 | return path1 === path2 || path2.startsWith(path1 + '.');
14 | };
15 |
--------------------------------------------------------------------------------
/lib/helpers/isObject.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * Determines if `arg` is an object.
5 | *
6 | * @param {Object|Array|String|Function|RegExp|any} arg
7 | * @api private
8 | * @return {Boolean}
9 | */
10 |
11 | module.exports = function(arg) {
12 | return (
13 | Buffer.isBuffer(arg) ||
14 | Object.prototype.toString.call(arg) === '[object Object]'
15 | );
16 | };
17 |
--------------------------------------------------------------------------------
/lib/helpers/query/sanitizeProjection.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = function sanitizeProjection(projection) {
4 | if (projection == null) {
5 | return;
6 | }
7 |
8 | const keys = Object.keys(projection);
9 | for (let i = 0; i < keys.length; ++i) {
10 | if (typeof projection[keys[i]] === 'string') {
11 | projection[keys[i]] = 1;
12 | }
13 | }
14 | };
15 |
--------------------------------------------------------------------------------
/lib/index.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /*!
4 | * Module dependencies.
5 | */
6 |
7 | const mongodbDriver = require('./drivers/node-mongodb-native');
8 |
9 | require('./driver').set(mongodbDriver);
10 |
11 | const mongoose = require('./mongoose');
12 |
13 | mongoose.setDriver(mongodbDriver);
14 |
15 | mongoose.Mongoose.prototype.mongo = require('mongodb');
16 |
17 | module.exports = mongoose;
18 |
--------------------------------------------------------------------------------
/test/esm.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const mongoose = require('../');
4 | const assert = require('assert');
5 |
6 | describe('esm:', function() {
7 | it('should have default export', function() {
8 | assert.deepEqual(mongoose, mongoose.default);
9 | });
10 | it('should have mongoose export', function() {
11 | assert.deepEqual(mongoose, mongoose.mongoose);
12 | });
13 | });
14 |
--------------------------------------------------------------------------------
/test/types/connect.test.ts:
--------------------------------------------------------------------------------
1 | import mongoose, { connect } from 'mongoose';
2 | import { expectType } from 'tsd';
3 |
4 | // Promise
5 | expectType>(connect('mongodb://127.0.0.1:27017/test'));
6 | expectType>(connect('mongodb://127.0.0.1:27017/test', {}));
7 | expectType>(connect('mongodb://127.0.0.1:27017/test', { bufferCommands: true }));
8 |
--------------------------------------------------------------------------------
/test/types/generics.test.ts:
--------------------------------------------------------------------------------
1 | import { Model, Document } from 'mongoose';
2 |
3 | class Repository {
4 | private readonly M: Model;
5 |
6 | constructor(MM: Model) {
7 | this.M = MM;
8 | }
9 |
10 | findById(id: string): Promise {
11 | return this.M.findById(id).orFail().exec();
12 | }
13 | }
14 |
15 | class Foo {
16 | name: string;
17 | }
18 |
19 | type Test = Repository;
20 |
--------------------------------------------------------------------------------
/lib/helpers/indexes/isTextIndex.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * Returns `true` if the given index options have a `text` option.
5 | */
6 |
7 | module.exports = function isTextIndex(indexKeys) {
8 | let isTextIndex = false;
9 | for (const key of Object.keys(indexKeys)) {
10 | if (indexKeys[key] === 'text') {
11 | isTextIndex = true;
12 | }
13 | }
14 |
15 | return isTextIndex;
16 | };
17 |
--------------------------------------------------------------------------------
/lib/helpers/getDefaultBulkwriteResult.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | function getDefaultBulkwriteResult() {
4 | return {
5 | ok: 1,
6 | nInserted: 0,
7 | nUpserted: 0,
8 | nMatched: 0,
9 | nModified: 0,
10 | nRemoved: 0,
11 | upserted: [],
12 | writeErrors: [],
13 | insertedIds: [],
14 | writeConcernErrors: []
15 | };
16 | }
17 |
18 | module.exports = getDefaultBulkwriteResult;
19 |
--------------------------------------------------------------------------------
/lib/helpers/schema/cleanPositionalOperators.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * For consistency's sake, we replace positional operator `$` and array filters
5 | * `$[]` and `$[foo]` with `0` when looking up schema paths.
6 | */
7 |
8 | module.exports = function cleanPositionalOperators(path) {
9 | return path.
10 | replace(/\.\$(\[[^\]]*\])?(?=\.)/g, '.0').
11 | replace(/\.\$(\[[^\]]*\])?$/g, '.0');
12 | };
13 |
--------------------------------------------------------------------------------
/lib/helpers/getConstructorName.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * If `val` is an object, returns constructor name, if possible. Otherwise returns undefined.
5 | * @api private
6 | */
7 |
8 | module.exports = function getConstructorName(val) {
9 | if (val == null) {
10 | return void 0;
11 | }
12 | if (typeof val.constructor !== 'function') {
13 | return void 0;
14 | }
15 | return val.constructor.name;
16 | };
17 |
--------------------------------------------------------------------------------
/lib/helpers/schema/applyBuiltinPlugins.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const builtinPlugins = require('../../plugins');
4 |
5 | module.exports = function applyBuiltinPlugins(schema) {
6 | for (const plugin of Object.values(builtinPlugins)) {
7 | plugin(schema, { deduplicate: true });
8 | }
9 | schema.plugins = Object.values(builtinPlugins).
10 | map(fn => ({ fn, opts: { deduplicate: true } })).
11 | concat(schema.plugins);
12 | };
13 |
--------------------------------------------------------------------------------
/lib/helpers/indexes/applySchemaCollation.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const isTextIndex = require('./isTextIndex');
4 |
5 | module.exports = function applySchemaCollation(indexKeys, indexOptions, schemaOptions) {
6 | if (isTextIndex(indexKeys)) {
7 | return;
8 | }
9 |
10 | if (Object.hasOwn(schemaOptions, 'collation') && !Object.hasOwn(indexOptions, 'collation')) {
11 | indexOptions.collation = schemaOptions.collation;
12 | }
13 | };
14 |
--------------------------------------------------------------------------------
/lib/helpers/model/pushNestedArrayPaths.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = function pushNestedArrayPaths(paths, nestedArray, path) {
4 | if (nestedArray == null) {
5 | return;
6 | }
7 |
8 | for (let i = 0; i < nestedArray.length; ++i) {
9 | if (Array.isArray(nestedArray[i])) {
10 | pushNestedArrayPaths(paths, nestedArray[i], path + '.' + i);
11 | } else {
12 | paths.push(path + '.' + i);
13 | }
14 | }
15 | };
16 |
--------------------------------------------------------------------------------
/lib/helpers/query/hasDollarKeys.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /*!
4 | * ignore
5 | */
6 |
7 | module.exports = function hasDollarKeys(obj) {
8 |
9 | if (typeof obj !== 'object' || obj === null) {
10 | return false;
11 | }
12 |
13 | const keys = Object.keys(obj);
14 | const len = keys.length;
15 |
16 | for (let i = 0; i < len; ++i) {
17 | if (keys[i][0] === '$') {
18 | return true;
19 | }
20 | }
21 |
22 | return false;
23 | };
24 |
--------------------------------------------------------------------------------
/lib/helpers/topology/allServersUnknown.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const getConstructorName = require('../getConstructorName');
4 |
5 | module.exports = function allServersUnknown(topologyDescription) {
6 | if (getConstructorName(topologyDescription) !== 'TopologyDescription') {
7 | return false;
8 | }
9 |
10 | const servers = Array.from(topologyDescription.servers.values());
11 | return servers.length > 0 && servers.every(server => server.type === 'Unknown');
12 | };
13 |
--------------------------------------------------------------------------------
/lib/helpers/path/parentPaths.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const dotRE = /\./g;
4 | module.exports = function parentPaths(path) {
5 | if (path.indexOf('.') === -1) {
6 | return [path];
7 | }
8 | const pieces = path.split(dotRE);
9 | const len = pieces.length;
10 | const ret = new Array(len);
11 | let cur = '';
12 | for (let i = 0; i < len; ++i) {
13 | cur += (cur.length !== 0) ? '.' + pieces[i] : pieces[i];
14 | ret[i] = cur;
15 | }
16 |
17 | return ret;
18 | };
19 |
--------------------------------------------------------------------------------
/test/types/mongo.test.ts:
--------------------------------------------------------------------------------
1 | import * as mongoose from 'mongoose';
2 | import { expectType } from 'tsd';
3 | import * as bson from 'bson';
4 |
5 | function gh12537() {
6 | const schema = new mongoose.Schema({ test: String });
7 | const model = mongoose.model('Test', schema);
8 |
9 | const doc = new model({});
10 |
11 | const v = new bson.ObjectId('somehex');
12 | expectType(v._id.toHexString());
13 |
14 | doc._id = new bson.ObjectId('somehex');
15 | }
16 |
17 | gh12537();
18 |
--------------------------------------------------------------------------------
/lib/helpers/isPOJO.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = function isPOJO(arg) {
4 | if (arg == null || typeof arg !== 'object') {
5 | return false;
6 | }
7 | const proto = Object.getPrototypeOf(arg);
8 | // Prototype may be null if you used `Object.create(null)`
9 | // Checking `proto`'s constructor is safe because `getPrototypeOf()`
10 | // explicitly crosses the boundary from object data to object metadata
11 | return !proto || proto.constructor.name === 'Object';
12 | };
13 |
--------------------------------------------------------------------------------
/lib/helpers/populate/validateRef.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const MongooseError = require('../../error/mongooseError');
4 | const util = require('util');
5 |
6 | module.exports = validateRef;
7 |
8 | function validateRef(ref, path) {
9 | if (typeof ref === 'string') {
10 | return;
11 | }
12 |
13 | if (typeof ref === 'function') {
14 | return;
15 | }
16 |
17 | throw new MongooseError('Invalid ref at path "' + path + '". Got ' +
18 | util.inspect(ref, { depth: 0 }));
19 | }
20 |
--------------------------------------------------------------------------------
/lib/helpers/schema/handleTimestampOption.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = handleTimestampOption;
4 |
5 | /*!
6 | * ignore
7 | */
8 |
9 | function handleTimestampOption(arg, prop) {
10 | if (arg == null) {
11 | return null;
12 | }
13 |
14 | if (typeof arg === 'boolean') {
15 | return prop;
16 | }
17 | if (typeof arg[prop] === 'boolean') {
18 | return arg[prop] ? prop : null;
19 | }
20 | if (!(prop in arg)) {
21 | return prop;
22 | }
23 | return arg[prop];
24 | }
25 |
--------------------------------------------------------------------------------
/lib/helpers/error/combinePathErrors.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /*!
4 | * ignore
5 | */
6 |
7 | module.exports = function combinePathErrors(err) {
8 | const keys = Object.keys(err.errors || {});
9 | const len = keys.length;
10 | const msgs = [];
11 | let key;
12 |
13 | for (let i = 0; i < len; ++i) {
14 | key = keys[i];
15 | if (err === err.errors[key]) {
16 | continue;
17 | }
18 | msgs.push(key + ': ' + err.errors[key].message);
19 | }
20 |
21 | return msgs.join(', ');
22 | };
23 |
--------------------------------------------------------------------------------
/lib/helpers/omitUndefined.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = function omitUndefined(val) {
4 | if (val == null || typeof val !== 'object') {
5 | return val;
6 | }
7 | if (Array.isArray(val)) {
8 | for (let i = val.length - 1; i >= 0; --i) {
9 | if (val[i] === undefined) {
10 | val.splice(i, 1);
11 | }
12 | }
13 | }
14 | for (const key of Object.keys(val)) {
15 | if (val[key] === void 0) {
16 | delete val[key];
17 | }
18 | }
19 | return val;
20 | };
21 |
--------------------------------------------------------------------------------
/test/helpers/projection.isExclusive.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const assert = require('assert');
4 |
5 | require('../common'); // required for side-effect setup (so that the default driver is set-up)
6 | const isExclusive = require('../../lib/helpers/projection/isExclusive');
7 |
8 | describe('isExclusive', function() {
9 | it('handles $elemMatch (gh-14893)', function() {
10 | assert.strictEqual(isExclusive({ field: { $elemMatch: { test: new Date('2024-06-01') } }, otherProp: 1 }), false);
11 | });
12 | });
13 |
--------------------------------------------------------------------------------
/test/helpers/projection.isInclusive.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const assert = require('assert');
4 |
5 | require('../common'); // required for side-effect setup (so that the default driver is set-up)
6 | const isInclusive = require('../../lib/helpers/projection/isInclusive');
7 |
8 | describe('isInclusive', function() {
9 | it('handles $elemMatch (gh-14893)', function() {
10 | assert.strictEqual(isInclusive({ field: { $elemMatch: { test: new Date('2024-06-01') } }, otherProp: 1 }), true);
11 | });
12 | });
13 |
--------------------------------------------------------------------------------
/scripts/tsc-diagnostics-check.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const fs = require('fs');
4 |
5 | const stdin = fs.readFileSync(0).toString('utf8');
6 | const maxInstantiations = isNaN(process.argv[2]) ? 400000 : parseInt(process.argv[2], 10);
7 |
8 | console.log(stdin);
9 |
10 | const numInstantiations = parseInt(stdin.match(/Instantiations:\s+(\d+)/)[1], 10);
11 | if (numInstantiations > maxInstantiations) {
12 | throw new Error(`Instantiations ${numInstantiations} > max ${maxInstantiations}`);
13 | }
14 |
15 | process.exit(0);
16 |
--------------------------------------------------------------------------------
/lib/helpers/discriminator/areDiscriminatorValuesEqual.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const isBsonType = require('../isBsonType');
4 |
5 | module.exports = function areDiscriminatorValuesEqual(a, b) {
6 | if (typeof a === 'string' && typeof b === 'string') {
7 | return a === b;
8 | }
9 | if (typeof a === 'number' && typeof b === 'number') {
10 | return a === b;
11 | }
12 | if (isBsonType(a, 'ObjectId') && isBsonType(b, 'ObjectId')) {
13 | return a.toString() === b.toString();
14 | }
15 | return false;
16 | };
17 |
--------------------------------------------------------------------------------
/lib/helpers/schema/handleIdOption.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const addAutoId = require('./addAutoId');
4 |
5 | module.exports = function handleIdOption(schema, options) {
6 | if (options == null || options._id == null) {
7 | return schema;
8 | }
9 |
10 | schema = schema.clone();
11 | if (!options._id) {
12 | schema.remove('_id');
13 | schema.options._id = false;
14 | } else if (!schema.paths['_id']) {
15 | addAutoId(schema);
16 | schema.options._id = true;
17 | }
18 |
19 | return schema;
20 | };
21 |
--------------------------------------------------------------------------------
/benchmarks/typescript/simple/index.ts:
--------------------------------------------------------------------------------
1 | import { Schema, Model, model } from 'mongoose';
2 |
3 | interface User {
4 | name: string;
5 | email: string;
6 | avatar?: string;
7 | }
8 |
9 | interface UserModelInterface extends Model {
10 | fetchUser(name: string): Promise;
11 | }
12 |
13 | const schema = new Schema({
14 | name: { type: String, required: true },
15 | email: { type: String, required: true },
16 | avatar: String
17 | });
18 |
19 | const UserModel = model('User', schema);
20 |
--------------------------------------------------------------------------------
/lib/helpers/query/handleReadPreferenceAliases.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = function handleReadPreferenceAliases(pref) {
4 | switch (pref) {
5 | case 'p':
6 | pref = 'primary';
7 | break;
8 | case 'pp':
9 | pref = 'primaryPreferred';
10 | break;
11 | case 's':
12 | pref = 'secondary';
13 | break;
14 | case 'sp':
15 | pref = 'secondaryPreferred';
16 | break;
17 | case 'n':
18 | pref = 'nearest';
19 | break;
20 | }
21 |
22 | return pref;
23 | };
24 |
--------------------------------------------------------------------------------
/lib/helpers/each.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = function each(arr, cb, done) {
4 | if (arr.length === 0) {
5 | return done();
6 | }
7 |
8 | let remaining = arr.length;
9 | let err = null;
10 | for (const v of arr) {
11 | cb(v, function(_err) {
12 | if (err != null) {
13 | return;
14 | }
15 | if (_err != null) {
16 | err = _err;
17 | return done(err);
18 | }
19 |
20 | if (--remaining <= 0) {
21 | return done();
22 | }
23 | });
24 | }
25 | };
26 |
--------------------------------------------------------------------------------
/docs/advanced_schemas.md:
--------------------------------------------------------------------------------
1 | # Advanced Schemas
2 |
3 | ## Creating from ES6 Classes Using `loadClass()`
4 |
5 | Mongoose allows creating schemas from [ES6 classes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes).
6 | The `loadClass()` function lets you pull in methods,
7 | statics, and virtuals from an ES6 class. A class method maps to a schema
8 | method, a static method maps to a schema static, and getters/setters map
9 | to virtuals.
10 |
11 | ```acquit
12 | [require:Creating from ES6 Classes Using `loadClass\(\)`]
13 | ```
14 |
--------------------------------------------------------------------------------
/lib/helpers/projection/isDefiningProjection.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /*!
4 | * ignore
5 | */
6 |
7 | module.exports = function isDefiningProjection(val) {
8 | if (val == null) {
9 | // `undefined` or `null` become exclusive projections
10 | return true;
11 | }
12 | if (typeof val === 'object') {
13 | // Only cases where a value does **not** define whether the whole projection
14 | // is inclusive or exclusive are `$meta` and `$slice`.
15 | return !('$meta' in val) && !('$slice' in val);
16 | }
17 | return true;
18 | };
19 |
--------------------------------------------------------------------------------
/lib/helpers/indexes/isDefaultIdIndex.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const get = require('../get');
4 |
5 | module.exports = function isDefaultIdIndex(index) {
6 | if (Array.isArray(index)) {
7 | // Mongoose syntax
8 | const keys = Object.keys(index[0]);
9 | return keys.length === 1 && keys[0] === '_id' && index[0]._id !== 'hashed';
10 | }
11 |
12 | if (typeof index !== 'object') {
13 | return false;
14 | }
15 |
16 | const key = get(index, 'key', {});
17 | return Object.keys(key).length === 1 && Object.hasOwn(key, '_id');
18 | };
19 |
--------------------------------------------------------------------------------
/lib/schema/operators/type.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /*!
4 | * ignore
5 | */
6 |
7 | module.exports = function(val) {
8 | if (Array.isArray(val)) {
9 | if (!val.every(v => typeof v === 'number' || typeof v === 'string')) {
10 | throw new Error('$type array values must be strings or numbers');
11 | }
12 | return val;
13 | }
14 |
15 | if (typeof val !== 'number' && typeof val !== 'string') {
16 | throw new Error('$type parameter must be number, string, or array of numbers and strings');
17 | }
18 |
19 | return val;
20 | };
21 |
--------------------------------------------------------------------------------
/lib/helpers/isSimpleValidator.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * Determines if `arg` is a flat object.
5 | *
6 | * @param {Object|Array|String|Function|RegExp|any} arg
7 | * @api private
8 | * @return {Boolean}
9 | */
10 |
11 | module.exports = function isSimpleValidator(obj) {
12 | const keys = Object.keys(obj);
13 | let result = true;
14 | for (let i = 0, len = keys.length; i < len; ++i) {
15 | if (typeof obj[keys[i]] === 'object' && obj[keys[i]] !== null) {
16 | result = false;
17 | break;
18 | }
19 | }
20 |
21 | return result;
22 | };
23 |
--------------------------------------------------------------------------------
/docs/incompatible_packages.md:
--------------------------------------------------------------------------------
1 | # Incompatible packages
2 |
3 | The following npm packages are known to be incompatible with Mongoose:
4 |
5 | * [collections](https://www.npmjs.com/package/collections): polluted globals cause issues with the MongoDB Node driver's URL parser. See [GitHub issue 12671](https://github.com/Automattic/mongoose/issues/12671#issuecomment-1374942680). This affects any [package that depends on collections](https://www.npmjs.com/package/collections?activeTab=dependents).
6 | * [excel-export](https://www.npmjs.com/package/excel-export): has dependency on `collections`
7 |
--------------------------------------------------------------------------------
/lib/helpers/immediate.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Centralize this so we can more easily work around issues with people
3 | * stubbing out `process.nextTick()` in tests using sinon:
4 | * https://github.com/sinonjs/lolex#automatically-incrementing-mocked-time
5 | * See gh-6074
6 | */
7 |
8 | 'use strict';
9 |
10 | const nextTick = typeof process !== 'undefined' && typeof process.nextTick === 'function' ?
11 | process.nextTick.bind(process) :
12 | cb => setTimeout(cb, 0); // Fallback for browser build
13 |
14 | module.exports = function immediate(cb) {
15 | return nextTick(cb);
16 | };
17 |
--------------------------------------------------------------------------------
/docs/images/tidelift.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/test/types/collection.test.ts:
--------------------------------------------------------------------------------
1 | import { Schema, model, Document, connection, Collection } from 'mongoose';
2 |
3 | const schema = new Schema({ name: { type: 'String' } });
4 |
5 | interface ITest {
6 | name?: string;
7 | age?: number;
8 | }
9 |
10 | const Test = model('Test', schema);
11 |
12 | Test.collection.collectionName;
13 | Test.collection.findOne({});
14 | Test.collection.findOneAndDelete({});
15 | Test.collection.ensureIndex();
16 | Test.collection.findAndModify();
17 | Test.collection.getIndexes();
18 |
19 | const coll: Collection = connection.collection('test');
20 |
--------------------------------------------------------------------------------
/lib/helpers/indexes/isTimeseriesIndex.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * Returns `true` if the given index matches the schema's `timestamps` options
5 | */
6 |
7 | module.exports = function isTimeseriesIndex(dbIndex, schemaOptions) {
8 | if (schemaOptions.timeseries == null) {
9 | return false;
10 | }
11 | const { timeField, metaField } = schemaOptions.timeseries;
12 | if (typeof timeField !== 'string' || typeof metaField !== 'string') {
13 | return false;
14 | }
15 | return Object.keys(dbIndex.key).length === 2 && dbIndex.key[timeField] === 1 && dbIndex.key[metaField] === 1;
16 | };
17 |
--------------------------------------------------------------------------------
/lib/types/index.js:
--------------------------------------------------------------------------------
1 |
2 | /*!
3 | * Module exports.
4 | */
5 |
6 | 'use strict';
7 |
8 | exports.Array = require('./array');
9 | exports.Buffer = require('./buffer');
10 |
11 | exports.Document = // @deprecate
12 | exports.Embedded = require('./arraySubdocument');
13 |
14 | exports.DocumentArray = require('./documentArray');
15 | exports.Double = require('./double');
16 | exports.Decimal128 = require('./decimal128');
17 | exports.ObjectId = require('./objectid');
18 |
19 | exports.Map = require('./map');
20 |
21 | exports.Subdocument = require('./subdocument');
22 |
23 | exports.UUID = require('./uuid');
24 |
--------------------------------------------------------------------------------
/lib/helpers/discriminator/checkEmbeddedDiscriminatorKeyProjection.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = function checkEmbeddedDiscriminatorKeyProjection(userProjection, path, schema, selected, addedPaths) {
4 | const userProjectedInPath = Object.keys(userProjection).
5 | reduce((cur, key) => cur || key.startsWith(path + '.'), false);
6 | const _discriminatorKey = path + '.' + schema.options.discriminatorKey;
7 | if (!userProjectedInPath &&
8 | addedPaths.length === 1 &&
9 | addedPaths[0] === _discriminatorKey) {
10 | selected.splice(selected.indexOf(_discriminatorKey), 1);
11 | }
12 | };
13 |
--------------------------------------------------------------------------------
/test/virtualtype.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const assert = require('assert');
4 | const start = require('./common');
5 |
6 | describe('VirtualType', function() {
7 | describe('clone', function() {
8 | it('copies path and options correctly (gh-8587)', function() {
9 | const opts = { ref: 'User', localField: 'userId', foreignField: '_id' };
10 | const virtual = new start.mongoose.VirtualType(Object.assign({}, opts), 'users');
11 |
12 | const clone = virtual.clone();
13 | assert.equal(clone.path, 'users');
14 | assert.deepEqual(clone.options, opts);
15 | });
16 | });
17 | });
18 |
--------------------------------------------------------------------------------
/test/schemaname.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const assert = require('assert');
4 | const start = require('./common');
5 | const Schema = start.mongoose.Schema;
6 |
7 | describe('schemaname', function() {
8 | it('exists on constructor', function() {
9 | const schema = new Schema({ name: String });
10 | const name = schema.path('name');
11 | assert.equal(name.constructor.schemaName, 'String');
12 | });
13 | it('exists on instance', function() {
14 | const schema = new Schema({ name: String });
15 | const name = schema.path('name');
16 | assert.equal(name.schemaName, 'String');
17 | });
18 | });
19 |
--------------------------------------------------------------------------------
/lib/error/browserMissingSchema.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Module dependencies.
3 | */
4 |
5 | 'use strict';
6 |
7 | const MongooseError = require('./mongooseError');
8 |
9 | /**
10 | * MissingSchema Error constructor.
11 | */
12 |
13 | class MissingSchemaError extends MongooseError {
14 |
15 | constructor() {
16 | super('Schema hasn\'t been registered for document.\n'
17 | + 'Use mongoose.Document(name, schema)');
18 | }
19 | }
20 |
21 | Object.defineProperty(MissingSchemaError.prototype, 'name', {
22 | value: 'MongooseError'
23 | });
24 |
25 | /*!
26 | * exports
27 | */
28 |
29 | module.exports = MissingSchemaError;
30 |
--------------------------------------------------------------------------------
/lib/error/overwriteModel.js:
--------------------------------------------------------------------------------
1 |
2 | /*!
3 | * Module dependencies.
4 | */
5 |
6 | 'use strict';
7 |
8 | const MongooseError = require('./mongooseError');
9 |
10 | /**
11 | * OverwriteModel Error constructor.
12 | * @param {String} name
13 | * @api private
14 | */
15 |
16 | class OverwriteModelError extends MongooseError {
17 |
18 | constructor(name) {
19 | super('Cannot overwrite `' + name + '` model once compiled.');
20 | }
21 | }
22 |
23 | Object.defineProperty(OverwriteModelError.prototype, 'name', {
24 | value: 'OverwriteModelError'
25 | });
26 |
27 | /*!
28 | * exports
29 | */
30 |
31 | module.exports = OverwriteModelError;
32 |
--------------------------------------------------------------------------------
/lib/error/createCollectionsError.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const MongooseError = require('./mongooseError');
4 |
5 | /**
6 | * createCollections Error constructor
7 | *
8 | * @param {String} message
9 | * @param {String} errorsMap
10 | * @inherits MongooseError
11 | * @api private
12 | */
13 |
14 | class CreateCollectionsError extends MongooseError {
15 | constructor(message, errorsMap) {
16 | super(message);
17 | this.errors = errorsMap;
18 | }
19 | }
20 |
21 | Object.defineProperty(CreateCollectionsError.prototype, 'name', {
22 | value: 'CreateCollectionsError'
23 | });
24 |
25 | module.exports = CreateCollectionsError;
26 |
27 |
--------------------------------------------------------------------------------
/lib/helpers/topology/isSSLError.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const getConstructorName = require('../getConstructorName');
4 |
5 | const nonSSLMessage = 'Client network socket disconnected before secure TLS ' +
6 | 'connection was established';
7 |
8 | module.exports = function isSSLError(topologyDescription) {
9 | if (getConstructorName(topologyDescription) !== 'TopologyDescription') {
10 | return false;
11 | }
12 |
13 | const descriptions = Array.from(topologyDescription.servers.values());
14 | return descriptions.length > 0 &&
15 | descriptions.every(descr => descr.error && descr.error.message.indexOf(nonSSLMessage) !== -1);
16 | };
17 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 |
4 |
5 | **Summary**
6 |
7 |
8 |
9 | **Examples**
10 |
11 |
12 |
--------------------------------------------------------------------------------
/lib/error/syncIndexes.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /*!
4 | * Module dependencies.
5 | */
6 |
7 | const MongooseError = require('./mongooseError');
8 |
9 | /**
10 | * SyncIndexes Error constructor.
11 | *
12 | * @param {String} message
13 | * @param {String} errorsMap
14 | * @inherits MongooseError
15 | * @api private
16 | */
17 |
18 | class SyncIndexesError extends MongooseError {
19 | constructor(message, errorsMap) {
20 | super(message);
21 | this.errors = errorsMap;
22 | }
23 | }
24 |
25 | Object.defineProperty(SyncIndexesError.prototype, 'name', {
26 | value: 'SyncIndexesError'
27 | });
28 |
29 |
30 | module.exports = SyncIndexesError;
31 |
--------------------------------------------------------------------------------
/lib/schema/operators/helpers.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /*!
4 | * Module requirements.
5 | */
6 |
7 | const SchemaNumber = require('../number');
8 |
9 | /*!
10 | * ignore
11 | */
12 |
13 | exports.castToNumber = castToNumber;
14 | exports.castArraysOfNumbers = castArraysOfNumbers;
15 |
16 | /*!
17 | * ignore
18 | */
19 |
20 | function castToNumber(val) {
21 | return SchemaNumber.cast()(val);
22 | }
23 |
24 | function castArraysOfNumbers(arr, self) {
25 | arr.forEach(function(v, i) {
26 | if (Array.isArray(v)) {
27 | castArraysOfNumbers(v, self);
28 | } else {
29 | arr[i] = castToNumber.call(self, v);
30 | }
31 | });
32 | }
33 |
--------------------------------------------------------------------------------
/test/helpers/update.applyTimestampsToUpdate.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const applyTimestampsToUpdate = require('../../lib/helpers/update/applyTimestampsToUpdate');
4 | const assert = require('assert');
5 |
6 | describe('applyTimestampsToUpdate', function() {
7 | it('handles update pipelines (gh-11151)', function() {
8 | const update = [{ $set: { title: 'mongoose-with-aggregate-set' } }];
9 | const now = new Date('2016-01-01');
10 | const res = applyTimestampsToUpdate(now, 'created_at', 'updated_at', update, {});
11 |
12 | assert.equal(res.length, 2);
13 | assert.equal(res[1].$set.updated_at.valueOf(), now.valueOf());
14 | });
15 | });
16 |
--------------------------------------------------------------------------------
/lib/helpers/isMongooseObject.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const isMongooseArray = require('../types/array/isMongooseArray').isMongooseArray;
4 | /**
5 | * Returns if `v` is a mongoose object that has a `toObject()` method we can use.
6 | *
7 | * This is for compatibility with libs like Date.js which do foolish things to Natives.
8 | *
9 | * @param {Any} v
10 | * @api private
11 | */
12 |
13 | module.exports = function(v) {
14 | return (
15 | v != null && (
16 | isMongooseArray(v) || // Array or Document Array
17 | v.$__ != null || // Document
18 | v.isMongooseBuffer || // Buffer
19 | v.$isMongooseMap // Map
20 | )
21 | );
22 | };
23 |
--------------------------------------------------------------------------------
/lib/connectionState.js:
--------------------------------------------------------------------------------
1 |
2 | /*!
3 | * Connection states
4 | */
5 |
6 | 'use strict';
7 |
8 | const STATES = module.exports = exports = Object.create(null);
9 |
10 | const disconnected = 'disconnected';
11 | const connected = 'connected';
12 | const connecting = 'connecting';
13 | const disconnecting = 'disconnecting';
14 | const uninitialized = 'uninitialized';
15 |
16 | STATES[0] = disconnected;
17 | STATES[1] = connected;
18 | STATES[2] = connecting;
19 | STATES[3] = disconnecting;
20 | STATES[99] = uninitialized;
21 |
22 | STATES[disconnected] = 0;
23 | STATES[connected] = 1;
24 | STATES[connecting] = 2;
25 | STATES[disconnecting] = 3;
26 | STATES[uninitialized] = 99;
27 |
--------------------------------------------------------------------------------
/lib/helpers/schema/applyReadConcern.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = function applyReadConcern(schema, options) {
4 | if (options.readConcern !== undefined) {
5 | return;
6 | }
7 |
8 | // Don't apply default read concern to operations in transactions,
9 | // because you shouldn't set read concern on individual operations
10 | // within a transaction.
11 | // See: https://www.mongodb.com/docs/manual/reference/read-concern/
12 | if (options && options.session && options.session.transaction) {
13 | return;
14 | }
15 |
16 | const level = schema.options?.readConcern?.level;
17 | if (level != null) {
18 | options.readConcern = { level };
19 | }
20 | };
21 |
--------------------------------------------------------------------------------
/test/helpers/update.removeUnusedArrayFilters.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const assert = require('assert');
4 | const removeUnusedArrayFilters = require('../../lib/helpers/update/removeUnusedArrayFilters');
5 |
6 | describe('removeUnusedArrayFilters', function() {
7 | it('respects `$or` (gh-10696)', function() {
8 | const update = {
9 | $set: {
10 | 'requests.$[i].status.aa': 'ON_GOING',
11 | 'requests.$[i].status.bb': 'ON_GOING'
12 | }
13 | };
14 | const arrayFilters = [{ $or: [{ 'i.no': 1 }] }];
15 |
16 | const ret = removeUnusedArrayFilters(update, arrayFilters);
17 | assert.deepEqual(ret, [{ $or: [{ 'i.no': 1 }] }]);
18 | });
19 | });
20 |
--------------------------------------------------------------------------------
/lib/error/parallelSave.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /*!
4 | * Module dependencies.
5 | */
6 |
7 | const MongooseError = require('./mongooseError');
8 |
9 |
10 | /**
11 | * ParallelSave Error constructor.
12 | *
13 | * @param {Document} doc
14 | * @api private
15 | */
16 |
17 | class ParallelSaveError extends MongooseError {
18 |
19 | constructor(doc) {
20 | const msg = 'Can\'t save() the same doc multiple times in parallel. Document: ';
21 | super(msg + doc._doc._id);
22 | }
23 | }
24 |
25 | Object.defineProperty(ParallelSaveError.prototype, 'name', {
26 | value: 'ParallelSaveError'
27 | });
28 |
29 | /*!
30 | * exports
31 | */
32 |
33 | module.exports = ParallelSaveError;
34 |
--------------------------------------------------------------------------------
/docs/css/carbonads.css:
--------------------------------------------------------------------------------
1 | /* CPM ads */
2 |
3 | .carbonad{
4 | margin-top:0!important;
5 | margin-bottom:-3rem!important
6 | }
7 |
8 | #carbonads {
9 | position:fixed;
10 | right: 0px;
11 | bottom: 0px;
12 | display:block;
13 | width:160px;
14 | padding:15px 15px 15px 150px;
15 | overflow:hidden;
16 | font-size:13px;
17 | line-height:1.4;
18 | text-align:left;
19 | background-color: #fafafa;
20 | }
21 |
22 | @media (max-width: 1170px) {
23 | #carbonads {
24 | display: none !important;
25 | }
26 | }
27 |
28 | #carbonads a{color:#333;text-decoration:none}
29 |
30 | .carbon-img{float:left;margin-left:-145px}
31 |
32 | .carbon-poweredby{display:block;color:#777!important}
33 |
--------------------------------------------------------------------------------
/lib/helpers/createJSONSchemaTypeDefinition.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * Handles creating `{ type: 'object' }` vs `{ bsonType: 'object' }` vs `{ bsonType: ['object', 'null'] }`
5 | *
6 | * @param {String} type
7 | * @param {String} bsonType
8 | * @param {Boolean} useBsonType
9 | * @param {Boolean} isRequired
10 | */
11 |
12 | module.exports = function createJSONSchemaTypeArray(type, bsonType, useBsonType, isRequired) {
13 | if (useBsonType) {
14 | if (isRequired) {
15 | return { bsonType };
16 | }
17 | return { bsonType: [bsonType, 'null'] };
18 | } else {
19 | if (isRequired) {
20 | return { type };
21 | }
22 | return { type: [type, 'null'] };
23 | }
24 | };
25 |
--------------------------------------------------------------------------------
/test/helpers/projection.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const assert = require('assert');
4 | const isSubpath = require('../../lib/helpers/projection/isSubpath');
5 |
6 | describe('isSubpath', function() {
7 | it('handles single-part paths', function(done) {
8 | assert.equal(isSubpath('a', 'a'), true);
9 | assert.equal(isSubpath('a', 'b'), false);
10 |
11 | done();
12 | });
13 |
14 | it('handles multi-part paths', function(done) {
15 | assert.equal(isSubpath('a.b.c', 'a.b.c'), true);
16 | assert.equal(isSubpath('a.c.b', 'a.b.c'), false);
17 | assert.equal(isSubpath('a', 'a.b.c'), true);
18 | assert.equal(isSubpath('a.b.c', 'a'), false);
19 |
20 | done();
21 | });
22 | });
23 |
--------------------------------------------------------------------------------
/test/types/methods.test.ts:
--------------------------------------------------------------------------------
1 | import { Schema, Model, connection } from 'mongoose';
2 |
3 | interface ITest {
4 | foo: string;
5 | }
6 |
7 | interface ITestMethods {
8 | getAnswer(): number;
9 | }
10 |
11 | type ITestModel = Model;
12 |
13 | const TestSchema = new Schema({
14 | foo: { type: String, required: true }
15 | });
16 |
17 | TestSchema.methods.getAnswer = function(): number {
18 | console.log(this.foo.trim());
19 | return 42;
20 | };
21 |
22 | const Test = connection.model('Test', TestSchema);
23 |
24 | Test.create({ foo: 'test' });
25 |
26 | const doc = new Test({ foo: 'test' });
27 |
28 | Math.floor(doc.getAnswer());
29 |
--------------------------------------------------------------------------------
/docs/includes/native.pug:
--------------------------------------------------------------------------------
1 | append style
2 | script(type="text/javascript" src="//m.servedby-buysellads.com/monetization.custom.js")
3 | link(rel="stylesheet", href=`${versions.versionedPath}/docs/css/inlinecpc.css`)
4 |
5 | #native-direct
6 | script.
7 | (function() {
8 | if (typeof _bsa !== 'undefined' && _bsa) {
9 | _bsa.init('custom', 'CK7DT53U', 'placement:mongoosejscom',
10 | {
11 | target: '#native-direct',
12 | template: `
13 |
16 |
17 | `
18 | }
19 | );
20 | }
21 | })();
22 |
--------------------------------------------------------------------------------
/docs/sponsors.pug:
--------------------------------------------------------------------------------
1 | extends layout
2 |
3 | block content
4 | div
5 | h1 Mongoose Sponsors
6 |
7 | each sponsor in sponsors
8 | div(style='position: relative; margin-top: 1em;')
9 | div(style='position: absolute; width: 100px; height: 100px')
10 | a(href=sponsor.url)
11 | img(src=sponsor.logo)
12 | div(style='padding-left: 110px; min-height: 100px')
13 | h3(style='margin-top: 0.2em; margin-bottom: 0.25em;')
14 | a(href=sponsor.url) #{sponsor.name}
15 | div !{sponsor.description}
16 |
17 |
18 | h2 Add Your Own
19 | div.
20 | Want to feature your app on this page?
21 | Sponsor Mongoose on GitHub!
22 |
--------------------------------------------------------------------------------
/lib/error/missingSchema.js:
--------------------------------------------------------------------------------
1 |
2 | /*!
3 | * Module dependencies.
4 | */
5 |
6 | 'use strict';
7 |
8 | const MongooseError = require('./mongooseError');
9 |
10 | /**
11 | * MissingSchema Error constructor.
12 | * @param {String} name
13 | * @api private
14 | */
15 |
16 | class MissingSchemaError extends MongooseError {
17 |
18 | constructor(name) {
19 | const msg = 'Schema hasn\'t been registered for model "' + name + '".\n'
20 | + 'Use mongoose.model(name, schema)';
21 | super(msg);
22 | }
23 | }
24 |
25 | Object.defineProperty(MissingSchemaError.prototype, 'name', {
26 | value: 'MissingSchemaError'
27 | });
28 |
29 | /*!
30 | * exports
31 | */
32 |
33 | module.exports = MissingSchemaError;
34 |
--------------------------------------------------------------------------------
/lib/error/parallelValidate.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /*!
4 | * Module dependencies.
5 | */
6 |
7 | const MongooseError = require('./mongooseError');
8 |
9 |
10 | /**
11 | * ParallelValidate Error constructor.
12 | *
13 | * @param {Document} doc
14 | * @api private
15 | */
16 |
17 | class ParallelValidateError extends MongooseError {
18 |
19 | constructor(doc) {
20 | const msg = 'Can\'t validate() the same doc multiple times in parallel. Document: ';
21 | super(msg + doc._doc._id);
22 | }
23 | }
24 |
25 | Object.defineProperty(ParallelValidateError.prototype, 'name', {
26 | value: 'ParallelValidateError'
27 | });
28 |
29 | /*!
30 | * exports
31 | */
32 |
33 | module.exports = ParallelValidateError;
34 |
--------------------------------------------------------------------------------
/lib/helpers/projection/isPathSelectedInclusive.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /*!
4 | * ignore
5 | */
6 |
7 | module.exports = function isPathSelectedInclusive(fields, path) {
8 | const chunks = path.split('.');
9 | let cur = '';
10 | let j;
11 | let keys;
12 | let numKeys;
13 | for (let i = 0; i < chunks.length; ++i) {
14 | cur += cur.length ? '.' : '' + chunks[i];
15 | if (fields[cur]) {
16 | keys = Object.keys(fields);
17 | numKeys = keys.length;
18 | for (j = 0; j < numKeys; ++j) {
19 | if (keys[i].indexOf(cur + '.') === 0 && keys[i].indexOf(path) !== 0) {
20 | continue;
21 | }
22 | }
23 | return true;
24 | }
25 | }
26 |
27 | return false;
28 | };
29 |
--------------------------------------------------------------------------------
/lib/cast/objectid.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const isBsonType = require('../helpers/isBsonType');
4 | const ObjectId = require('../types/objectid');
5 |
6 | module.exports = function castObjectId(value) {
7 | if (value == null) {
8 | return value;
9 | }
10 |
11 | if (isBsonType(value, 'ObjectId')) {
12 | return value;
13 | }
14 |
15 | if (value._id) {
16 | if (isBsonType(value._id, 'ObjectId')) {
17 | return value._id;
18 | }
19 | if (value._id.toString instanceof Function) {
20 | return new ObjectId(value._id.toString());
21 | }
22 | }
23 |
24 | if (value.toString instanceof Function) {
25 | return new ObjectId(value.toString());
26 | }
27 |
28 | return new ObjectId(value);
29 | };
30 |
--------------------------------------------------------------------------------
/test/types/helpers.test.ts:
--------------------------------------------------------------------------------
1 | import * as mongoose from 'mongoose';
2 | import { ObjectId } from 'mongodb';
3 | import { expectType, expectError } from 'tsd';
4 |
5 | expectType(mongoose.isObjectIdOrHexString(new ObjectId()));
6 | expectType(mongoose.isObjectIdOrHexString(new mongoose.Types.ObjectId()));
7 | expectType(mongoose.isObjectIdOrHexString('string'));
8 | expectType(mongoose.isObjectIdOrHexString(new Error()));
9 |
10 | expectType(mongoose.isValidObjectId(new ObjectId()));
11 | expectType(mongoose.isValidObjectId(new mongoose.Types.ObjectId()));
12 | expectType(mongoose.isValidObjectId('12345'));
13 | expectError(mongoose.isValidObjectId());
14 |
15 | expectType(mongoose.now());
16 |
--------------------------------------------------------------------------------
/tools/auth.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Server = require('mongodb-topology-manager').Server;
4 | const mongodb = require('mongodb');
5 |
6 | run().catch(error => {
7 | console.error(error);
8 | process.exit(-1);
9 | });
10 |
11 | async function run() {
12 | // Create new instance
13 | const server = new Server('mongod', {
14 | auth: null,
15 | dbpath: '/data/db/27017'
16 | });
17 |
18 | // Purge the directory
19 | await server.purge();
20 |
21 | // Start process
22 | await server.start();
23 |
24 | const db = await mongodb.MongoClient.connect('mongodb://127.0.0.1:27017/admin');
25 |
26 | await db.addUser('passwordIsTaco', 'taco', {
27 | roles: ['dbOwner']
28 | });
29 |
30 | console.log('done');
31 | }
32 |
--------------------------------------------------------------------------------
/lib/error/invalidSchemaOption.js:
--------------------------------------------------------------------------------
1 |
2 | /*!
3 | * Module dependencies.
4 | */
5 |
6 | 'use strict';
7 |
8 | const MongooseError = require('./mongooseError');
9 |
10 | /**
11 | * InvalidSchemaOption Error constructor.
12 | * @param {String} name
13 | * @api private
14 | */
15 |
16 | class InvalidSchemaOptionError extends MongooseError {
17 |
18 | constructor(name, option) {
19 | const msg = `Cannot create use schema for property "${name}" because the schema has the ${option} option enabled.`;
20 | super(msg);
21 | }
22 | }
23 |
24 | Object.defineProperty(InvalidSchemaOptionError.prototype, 'name', {
25 | value: 'InvalidSchemaOptionError'
26 | });
27 |
28 | /*!
29 | * exports
30 | */
31 |
32 | module.exports = InvalidSchemaOptionError;
33 |
--------------------------------------------------------------------------------
/lib/helpers/path/setDottedPath.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const specialProperties = require('../specialProperties');
4 |
5 |
6 | module.exports = function setDottedPath(obj, path, val) {
7 | if (path.indexOf('.') === -1) {
8 | if (specialProperties.has(path)) {
9 | return;
10 | }
11 |
12 | obj[path] = val;
13 | return;
14 | }
15 | const parts = path.split('.');
16 |
17 | const last = parts.pop();
18 | let cur = obj;
19 | for (const part of parts) {
20 | if (specialProperties.has(part)) {
21 | continue;
22 | }
23 | if (cur[part] == null) {
24 | cur[part] = {};
25 | }
26 |
27 | cur = cur[part];
28 | }
29 |
30 | if (!specialProperties.has(last)) {
31 | cur[last] = val;
32 | }
33 | };
34 |
--------------------------------------------------------------------------------
/lib/helpers/schema/idGetter.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /*!
4 | * ignore
5 | */
6 |
7 | module.exports = function addIdGetter(schema) {
8 | // ensure the documents receive an id getter unless disabled
9 | const autoIdGetter = !schema.paths['id'] &&
10 | schema.paths['_id'] &&
11 | schema.options.id;
12 | if (!autoIdGetter) {
13 | return schema;
14 | }
15 | if (schema.aliases && schema.aliases.id) {
16 | return schema;
17 | }
18 | schema.virtual('id').get(idGetter);
19 |
20 | return schema;
21 | };
22 |
23 | /**
24 | * Returns this documents _id cast to a string.
25 | * @api private
26 | */
27 |
28 | function idGetter() {
29 | if (this._id != null) {
30 | return this._id.toString();
31 | }
32 |
33 | return null;
34 | }
35 |
--------------------------------------------------------------------------------
/lib/helpers/indexes/decorateDiscriminatorIndexOptions.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = function decorateDiscriminatorIndexOptions(schema, indexOptions) {
4 | // If the model is a discriminator and has an index, add a
5 | // partialFilterExpression by default so the index will only apply
6 | // to that discriminator.
7 | const discriminatorName = schema.discriminatorMapping && schema.discriminatorMapping.value;
8 | if (discriminatorName && !('sparse' in indexOptions)) {
9 | const discriminatorKey = schema.options.discriminatorKey;
10 | indexOptions.partialFilterExpression = indexOptions.partialFilterExpression || {};
11 | indexOptions.partialFilterExpression[discriminatorKey] = discriminatorName;
12 | }
13 | return indexOptions;
14 | };
15 |
--------------------------------------------------------------------------------
/docs/search.pug:
--------------------------------------------------------------------------------
1 | extends layout
2 |
3 | append style
4 | style.
5 | .title {
6 | font-size: 1.5em;
7 | }
8 |
9 | ul {
10 | list-style-type: none;
11 | padding: 0px;
12 | }
13 |
14 | .url a {
15 | font-size: 0.75em;
16 | color: #777;
17 | margin-top: 0.5em;
18 | }
19 |
20 | p {
21 | margin-top: 0.5em;
22 | }
23 |
24 | block content
25 | div
26 | h1 Search
27 |
28 | include includes/native
29 |
30 | div.search
31 | input#search-input(type="text", placeholder="Search")
32 | button#search-button
33 | img(src=`${versions.versionedPath}/docs/images/search.svg`)
34 | div#results
35 |
36 | script(type="text/javascript" src=`${versions.versionedPath}/docs/js/search.js`)
37 |
--------------------------------------------------------------------------------
/lib/helpers/schema/getKeysInSchemaOrder.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const get = require('../get');
4 |
5 | module.exports = function getKeysInSchemaOrder(schema, val, path) {
6 | const schemaKeys = path != null ? Object.keys(get(schema.tree, path, {})) : Object.keys(schema.tree);
7 | const valKeys = new Set(Object.keys(val));
8 |
9 | let keys;
10 | if (valKeys.size > 1) {
11 | keys = new Set();
12 | for (const key of schemaKeys) {
13 | if (valKeys.has(key)) {
14 | keys.add(key);
15 | }
16 | }
17 | for (const key of valKeys) {
18 | if (!keys.has(key)) {
19 | keys.add(key);
20 | }
21 | }
22 | keys = Array.from(keys);
23 | } else {
24 | keys = Array.from(valKeys);
25 | }
26 |
27 | return keys;
28 | };
29 |
--------------------------------------------------------------------------------
/lib/error/objectExpected.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Module dependencies.
3 | */
4 |
5 | 'use strict';
6 |
7 | const MongooseError = require('./mongooseError');
8 |
9 | /**
10 | * Strict mode error constructor
11 | *
12 | * @param {string} type
13 | * @param {string} value
14 | * @api private
15 | */
16 |
17 | class ObjectExpectedError extends MongooseError {
18 |
19 | constructor(path, val) {
20 | const typeDescription = Array.isArray(val) ? 'array' : 'primitive value';
21 | super('Tried to set nested object field `' + path +
22 | `\` to ${typeDescription} \`` + val + '`');
23 | this.path = path;
24 | }
25 | }
26 |
27 | Object.defineProperty(ObjectExpectedError.prototype, 'name', {
28 | value: 'ObjectExpectedError'
29 | });
30 |
31 | module.exports = ObjectExpectedError;
32 |
--------------------------------------------------------------------------------
/lib/error/strictPopulate.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Module dependencies.
3 | */
4 |
5 | 'use strict';
6 |
7 | const MongooseError = require('./mongooseError');
8 |
9 | /**
10 | * Strict mode error constructor
11 | *
12 | * @param {String} path
13 | * @param {String} [msg]
14 | * @inherits MongooseError
15 | * @api private
16 | */
17 |
18 | class StrictPopulateError extends MongooseError {
19 |
20 | constructor(path, msg) {
21 | msg = msg || 'Cannot populate path `' + path + '` because it is not in your schema. ' + 'Set the `strictPopulate` option to false to override.';
22 | super(msg);
23 | this.path = path;
24 | }
25 | }
26 |
27 | Object.defineProperty(StrictPopulateError.prototype, 'name', {
28 | value: 'StrictPopulateError'
29 | });
30 |
31 | module.exports = StrictPopulateError;
32 |
--------------------------------------------------------------------------------
/test/helpers/getFunctionName.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const assert = require('assert');
4 | const getFunctionName = require('../../lib/helpers/getFunctionName');
5 |
6 | describe('getFunctionName', () => {
7 | it('return fn.name', () => {
8 | assert.equal(getFunctionName({ name: 'fnName' }), 'fnName');
9 | });
10 |
11 | it('return function name', () => {
12 | assert.equal(getFunctionName(function fnName() {}), 'fnName');
13 | });
14 |
15 | it('return function functionName', () => {
16 | assert.equal(getFunctionName(function functionName() {}), 'functionName');
17 | });
18 |
19 | it('return undefined for arrow function', () => {
20 | // I can't say it's expected behavior, but is how it's behave.
21 | assert.equal(getFunctionName(() => []), undefined);
22 | });
23 | });
24 |
--------------------------------------------------------------------------------
/.github/workflows/stale.yml:
--------------------------------------------------------------------------------
1 | name: "Close stale issues"
2 | on:
3 | schedule:
4 | - cron: "0 0 * * *"
5 | workflow_dispatch:
6 | permissions:
7 | issues: write
8 |
9 | jobs:
10 | stale:
11 | runs-on: ubuntu-latest
12 | steps:
13 | - name: stale
14 | uses: actions/stale@v10
15 | with:
16 | repo-token: ${{ secrets.GITHUB_TOKEN }}
17 | stale-issue-message: 'This issue is stale because it has been open 14 days with no activity. Remove stale label or comment or this will be closed in 5 days'
18 | close-issue-message: "This issue was closed because it has been inactive for 19 days and has been marked as stale."
19 | days-before-stale: 14
20 | days-before-close: 5
21 | any-of-labels: can't reproduce,help,needs clarification
22 |
--------------------------------------------------------------------------------
/lib/helpers/discriminator/getDiscriminatorByValue.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const areDiscriminatorValuesEqual = require('./areDiscriminatorValuesEqual');
4 |
5 | /**
6 | * returns discriminator by discriminatorMapping.value
7 | *
8 | * @param {Object} discriminators
9 | * @param {string} value
10 | * @api private
11 | */
12 |
13 | module.exports = function getDiscriminatorByValue(discriminators, value) {
14 | if (discriminators == null) {
15 | return null;
16 | }
17 | for (const name of Object.keys(discriminators)) {
18 | const it = discriminators[name];
19 | if (
20 | it.schema &&
21 | it.schema.discriminatorMapping &&
22 | areDiscriminatorValuesEqual(it.schema.discriminatorMapping.value, value)
23 | ) {
24 | return it;
25 | }
26 | }
27 | return null;
28 | };
29 |
--------------------------------------------------------------------------------
/lib/schema/operators/bitwise.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Module requirements.
3 | */
4 |
5 | 'use strict';
6 |
7 | const CastError = require('../../error/cast');
8 |
9 | /*!
10 | * ignore
11 | */
12 |
13 | function handleBitwiseOperator(val) {
14 | const _this = this;
15 | if (Array.isArray(val)) {
16 | return val.map(function(v) {
17 | return _castNumber(_this.path, v);
18 | });
19 | } else if (Buffer.isBuffer(val)) {
20 | return val;
21 | }
22 | // Assume trying to cast to number
23 | return _castNumber(_this.path, val);
24 | }
25 |
26 | /*!
27 | * ignore
28 | */
29 |
30 | function _castNumber(path, num) {
31 | const v = Number(num);
32 | if (isNaN(v)) {
33 | throw new CastError('number', num, path);
34 | }
35 | return v;
36 | }
37 |
38 | module.exports = handleBitwiseOperator;
39 |
--------------------------------------------------------------------------------
/test/helpers/common.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const assert = require('assert');
4 | const modifiedPaths = require('../../lib/helpers/common').modifiedPaths;
5 |
6 | describe('modifiedPaths, bad update value which has circular reference field', () => {
7 | it('update value can be null', function() {
8 | modifiedPaths(null, 'path', null);
9 | });
10 |
11 | it('values with obvious error on circular reference', function() {
12 | const objA = {};
13 | objA.a = objA;
14 |
15 | assert.throws(() => modifiedPaths(objA, 'path', null), /circular reference/);
16 | });
17 |
18 | it('values with multiple references which are not circular should succeed', function() {
19 | const objA = {};
20 | const objB = { a: objA, b: objA };
21 |
22 | modifiedPaths(objB, 'path', null);
23 | });
24 | });
25 |
--------------------------------------------------------------------------------
/lib/error/strict.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Module dependencies.
3 | */
4 |
5 | 'use strict';
6 |
7 | const MongooseError = require('./mongooseError');
8 |
9 | /**
10 | * Strict mode error constructor
11 | *
12 | * @param {String} path
13 | * @param {String} [msg]
14 | * @param {Boolean} [immutable]
15 | * @inherits MongooseError
16 | * @api private
17 | */
18 |
19 |
20 | class StrictModeError extends MongooseError {
21 |
22 | constructor(path, msg, immutable) {
23 | msg = msg || 'Field `' + path + '` is not in schema and strict ' +
24 | 'mode is set to throw.';
25 | super(msg);
26 | this.isImmutableError = !!immutable;
27 | this.path = path;
28 | }
29 | }
30 |
31 | Object.defineProperty(StrictModeError.prototype, 'name', {
32 | value: 'StrictModeError'
33 | });
34 |
35 | module.exports = StrictModeError;
36 |
--------------------------------------------------------------------------------
/lib/helpers/minimize.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const { isPOJO } = require('../utils');
4 |
5 | module.exports = minimize;
6 |
7 | /**
8 | * Minimizes an object, removing undefined values and empty objects
9 | *
10 | * @param {Object} object to minimize
11 | * @return {Object|undefined}
12 | * @api private
13 | */
14 |
15 | function minimize(obj) {
16 | const keys = Object.keys(obj);
17 | let i = keys.length;
18 | let hasKeys;
19 | let key;
20 | let val;
21 |
22 | while (i--) {
23 | key = keys[i];
24 | val = obj[key];
25 |
26 | if (isPOJO(val)) {
27 | obj[key] = minimize(val);
28 | }
29 |
30 | if (undefined === obj[key]) {
31 | delete obj[key];
32 | continue;
33 | }
34 |
35 | hasKeys = true;
36 | }
37 |
38 | return hasKeys
39 | ? obj
40 | : undefined;
41 | }
42 |
--------------------------------------------------------------------------------
/lib/helpers/parallelLimit.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = parallelLimit;
4 |
5 | /*!
6 | * ignore
7 | */
8 |
9 | async function parallelLimit(params, fn, limit) {
10 | if (limit <= 0) {
11 | throw new Error('Limit must be positive');
12 | }
13 |
14 | if (params.length === 0) {
15 | return [];
16 | }
17 |
18 | const results = [];
19 | const executing = new Set();
20 |
21 | for (let index = 0; index < params.length; index++) {
22 | const param = params[index];
23 | const p = fn(param, index);
24 | results.push(p);
25 |
26 | executing.add(p);
27 |
28 | const clean = () => executing.delete(p);
29 | p.then(clean).catch(clean);
30 |
31 | if (executing.size >= limit) {
32 | await Promise.race(executing);
33 | }
34 | }
35 |
36 | return Promise.all(results);
37 | }
38 |
--------------------------------------------------------------------------------
/test/helpers/applyWriteConcern.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const assert = require('assert');
4 | const applyWriteConcern = require('../../lib/helpers/schema/applyWriteConcern');
5 | const start = require('../common');
6 | const mongoose = start.mongoose;
7 |
8 | describe('applyWriteConcern', function() {
9 | let db;
10 | before(function() {
11 | db = start();
12 | });
13 | after(async function() {
14 | await db.close();
15 | });
16 | it('should not overwrite user specified writeConcern options (gh-13592)', async function() {
17 | const options = { writeConcern: { w: 'majority' } };
18 | const testSchema = new mongoose.Schema({ name: String }, { writeConcern: { w: 0 } });
19 | applyWriteConcern(testSchema, options);
20 | assert.deepStrictEqual({ writeConcern: { w: 'majority' } }, options);
21 | });
22 | });
23 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/other.yml:
--------------------------------------------------------------------------------
1 | name: ❔ Other
2 | description: Open an issue that is not feature or bug related
3 |
4 | body:
5 | - type: checkboxes
6 | id: prerequisites
7 | attributes:
8 | label: Prerequisites
9 | options:
10 | - label: I have written a descriptive issue title
11 | required: true
12 | - label: |
13 | I have searched existing issues to ensure the issue has not already been raised
14 | required: true
15 |
16 | - type: textarea
17 | id: text
18 | attributes:
19 | label: Issue
20 | description: |
21 | Give as much detail as you can to help us understand.
22 | Make sure you place example code inside a [code (```) block](https://docs.github.com/en/github/writing-on-github/creating-and-highlighting-code-blocks) to avoid linking unrelated issues.
--------------------------------------------------------------------------------
/lib/helpers/projection/parseProjection.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * Convert a string or array into a projection object, retaining all
5 | * `-` and `+` paths.
6 | */
7 |
8 | module.exports = function parseProjection(v, retainMinusPaths) {
9 | const type = typeof v;
10 |
11 | if (type === 'string') {
12 | v = v.split(/\s+/);
13 | }
14 | if (!Array.isArray(v) && Object.prototype.toString.call(v) !== '[object Arguments]') {
15 | return v;
16 | }
17 |
18 | const len = v.length;
19 | const ret = {};
20 | for (let i = 0; i < len; ++i) {
21 | let field = v[i];
22 | if (!field) {
23 | continue;
24 | }
25 | const include = '-' == field[0] ? 0 : 1;
26 | if (!retainMinusPaths && include === 0) {
27 | field = field.substring(1);
28 | }
29 | ret[field] = include;
30 | }
31 |
32 | return ret;
33 | };
34 |
--------------------------------------------------------------------------------
/test/types/Errors.test.ts:
--------------------------------------------------------------------------------
1 | import * as mongoose from 'mongoose';
2 |
3 | /**
4 | * gh-issue #11367
5 | *
6 | * @see https://github.com/Automattic/mongoose/issues/11367
7 | */
8 | function handleValidationError(err: mongoose.Error.ValidationError): Array {
9 | const errorTypes = Object.keys(err.errors).map((field: string) => err.errors[field].kind);
10 | return errorTypes;
11 | }
12 |
13 | /**
14 | * gh-issue #11838
15 | *
16 | * @see https://github.com/Automattic/mongoose/issues/11838
17 | */
18 | function gh11838() {
19 | const Model = mongoose.model('Test', new mongoose.Schema({ answer: Number }));
20 | const doc = new Model({ answer: 'not a number' });
21 | const err = doc.validateSync();
22 |
23 | err instanceof mongoose.Error;
24 | err instanceof mongoose.MongooseError;
25 | err instanceof mongoose.Error.ValidationError;
26 | }
27 |
--------------------------------------------------------------------------------
/.github/workflows/publish.yml:
--------------------------------------------------------------------------------
1 | name: Publish Package to npmjs
2 |
3 | on:
4 | release:
5 | types: [published]
6 | workflow_dispatch: # 👈 allows you to trigger manually from the Actions tab
7 |
8 | jobs:
9 | publish:
10 | runs-on: ubuntu-latest
11 | permissions:
12 | contents: read
13 | id-token: write
14 | steps:
15 | - name: Checkout repository
16 | uses: actions/checkout@v6.0.0
17 |
18 | - name: Setup Node.js
19 | uses: actions/setup-node@v6
20 | with:
21 | node-version: '24.x'
22 | registry-url: 'https://registry.npmjs.org'
23 |
24 | - name: Install dependencies
25 | run: npm install
26 |
27 | - name: Publish with provenance
28 | run: npm publish --provenance --access public
29 | env:
30 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
31 |
--------------------------------------------------------------------------------
/scripts/static.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const express = require('express');
4 | const app = express();
5 |
6 | const website = require('./website');
7 |
8 | const port = process.env.PORT
9 | ? parseInt(process.env.PORT, 10)
10 | : 8089;
11 |
12 | async function main() {
13 | await Promise.all([
14 | website.copyAllRequiredFiles(),
15 | website.pugifyAllFiles()
16 | ]);
17 | // start watching for file changes and re-compile them, so that they can be served directly
18 | website.startWatch();
19 |
20 | app.use('/', express.static(website.cwd));
21 |
22 | app.listen(port, () => {
23 | let urlPath = '/';
24 |
25 | if (website.versionObj.versionedDeploy) {
26 | urlPath = website.versionObj.versionedPath;
27 | }
28 |
29 | console.log(`now listening on http://127.0.0.1:${port}${urlPath}`);
30 | });
31 | }
32 |
33 | main();
34 |
--------------------------------------------------------------------------------
/lib/error/objectParameter.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Module dependencies.
3 | */
4 |
5 | 'use strict';
6 |
7 | const MongooseError = require('./mongooseError');
8 |
9 | /**
10 | * Constructor for errors that happen when a parameter that's expected to be
11 | * an object isn't an object
12 | *
13 | * @param {Any} value
14 | * @param {String} paramName
15 | * @param {String} fnName
16 | * @api private
17 | */
18 |
19 | class ObjectParameterError extends MongooseError {
20 | constructor(value, paramName, fnName) {
21 | super('Parameter "' + paramName + '" to ' + fnName +
22 | '() must be an object, got "' + (value == null ? value : value.toString()) + '" (type ' + typeof value + ')');
23 | }
24 | }
25 |
26 |
27 | Object.defineProperty(ObjectParameterError.prototype, 'name', {
28 | value: 'ObjectParameterError'
29 | });
30 |
31 | module.exports = ObjectParameterError;
32 |
--------------------------------------------------------------------------------
/test/helpers/schema.cleanPositionalOperators.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const assert = require('assert');
4 | const cleanPositionalOperators = require('../../lib/helpers/schema/cleanPositionalOperators');
5 |
6 | describe('cleanPositionalOperators', function() {
7 | it('replaces trailing array filter', function() {
8 | assert.equal(cleanPositionalOperators('questions.$[q]'), 'questions.0');
9 | });
10 |
11 | it('replaces trailing $', function() {
12 | assert.equal(cleanPositionalOperators('questions.$'), 'questions.0');
13 | });
14 |
15 | it('replaces interior array filters', function() {
16 | assert.equal(cleanPositionalOperators('questions.$[q].$[r].test'), 'questions.0.0.test');
17 | });
18 |
19 | it('replaces interior elemMatch', function() {
20 | assert.equal(cleanPositionalOperators('questions.$.$.test'), 'questions.0.0.test');
21 | });
22 | });
23 |
--------------------------------------------------------------------------------
/test/types/check-types-filename.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const fs = require('fs');
4 | const uppercaseRE = /[A-Z]/g;
5 |
6 | const checkFolder = (folder) => {
7 | const folderContent = fs.readdirSync(folder);
8 |
9 | for (const entry of folderContent) {
10 |
11 | if (fs.lstatSync(folder + '/' + entry).isDirectory()) {
12 | checkFolder(folder + '/' + entry);
13 | } else {
14 | if (entry === '.gitignore' || entry.endsWith('.d.ts')) {
15 | if (uppercaseRE.test(entry)) {
16 | console.error('File ' + entry + ' contains uppercase characters.\n');
17 | process.exit(1);
18 | }
19 | continue;
20 | } else {
21 | console.error('File ' + entry + ' does not have a valid extension, must be .d.ts or .gitignore.\n');
22 | process.exit(1);
23 | }
24 | }
25 | }
26 | };
27 |
28 | checkFolder('./types');
29 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | lib-cov
2 | **.swp
3 | *.sw*
4 | *.orig
5 | .DS_Store
6 | node_modules/
7 | benchmarks/
8 | docs/
9 | test/
10 | Makefile
11 | CNAME
12 | index.html
13 | index.pug
14 | bin/
15 | tools/31*
16 | *.key
17 | data/
18 |
19 | *.txt
20 | *.png
21 |
22 | examples/
23 | .github
24 | .vscode
25 | .eslintignore
26 | CONTRIBUTING.md
27 | History.md
28 | CHANGELOG.md
29 | format_deps.js
30 | release-items.md
31 | static.js
32 | website.js
33 |
34 | .config*
35 |
36 | migrating_to_6.md
37 | migrating_to_5.md
38 | renovate.json
39 | .travis.yml
40 | webpack.config.js
41 | webpack.base.config.js
42 |
43 | .nyc-output
44 |
45 | *.tgz
46 |
47 | notes.md
48 | list.out
49 |
50 | # config files
51 | lgtm.yml
52 | .mocharc.yml
53 | .eslintrc.js
54 | .markdownlint-cli2.cjs
55 | tsconfig.json
56 |
57 | # scripts
58 | scripts/
59 | tools/
60 |
61 | *.0x
62 | valnotes.md
63 |
64 | coverage
65 | .nyc_output
66 |
--------------------------------------------------------------------------------
/docs/js/redirect-old-api.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | window.addEventListener('DOMContentLoaded', () => {
3 | const anchor = window.location.hash;
4 |
5 | // in case there is not anchor
6 | if (!anchor) {
7 | return redirectToBase();
8 | }
9 |
10 | const firstName = anchor.split('_')[0];
11 |
12 | // in case there is no split
13 | if (!firstName) {
14 | return redirectToBase();
15 | }
16 |
17 | const sliced = firstName.slice(1).toLowerCase(); // ignore first character, which will always be "#"
18 |
19 | // in case everything after "#" is empty
20 | if (!sliced) {
21 | return redirectToBase();
22 | }
23 |
24 | window.location.replace('./api/' + sliced + '.html' + anchor);
25 | }, { once: true });
26 |
27 | // helper function to redirect in case no other redirect can be found
28 | function redirectToBase() {
29 | window.location.replace('./api/mongoose.html');
30 | }
31 |
--------------------------------------------------------------------------------
/lib/helpers/discriminator/getSchemaDiscriminatorByValue.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const areDiscriminatorValuesEqual = require('./areDiscriminatorValuesEqual');
4 |
5 | /**
6 | * returns discriminator by discriminatorMapping.value
7 | *
8 | * @param {Schema} schema
9 | * @param {string} value
10 | * @api private
11 | */
12 |
13 | module.exports = function getSchemaDiscriminatorByValue(schema, value) {
14 | if (schema == null || schema.discriminators == null) {
15 | return null;
16 | }
17 | for (const key of Object.keys(schema.discriminators)) {
18 | const discriminatorSchema = schema.discriminators[key];
19 | if (discriminatorSchema.discriminatorMapping == null) {
20 | continue;
21 | }
22 | if (areDiscriminatorValuesEqual(discriminatorSchema.discriminatorMapping.value, value)) {
23 | return discriminatorSchema;
24 | }
25 | }
26 | return null;
27 | };
28 |
--------------------------------------------------------------------------------
/lib/options/schemaUnionOptions.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const SchemaTypeOptions = require('./schemaTypeOptions');
4 |
5 | /**
6 | * The options defined on a Union schematype.
7 | *
8 | * @api public
9 | * @inherits SchemaTypeOptions
10 | * @constructor SchemaUnionOptions
11 | */
12 |
13 | class SchemaUnionOptions extends SchemaTypeOptions {}
14 |
15 | const opts = require('./propertyOptions');
16 |
17 | /**
18 | * If set, specifies the types that this union can take. Mongoose will cast
19 | * the value to one of the given types.
20 | *
21 | * If not set, Mongoose will not cast the value to any specific type.
22 | *
23 | * @api public
24 | * @property of
25 | * @memberOf SchemaUnionOptions
26 | * @type {Function|Function[]|string|string[]}
27 | * @instance
28 | */
29 |
30 | Object.defineProperty(SchemaUnionOptions.prototype, 'of', opts);
31 |
32 | module.exports = SchemaUnionOptions;
33 |
--------------------------------------------------------------------------------
/lib/helpers/topology/isAtlas.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const getConstructorName = require('../getConstructorName');
4 |
5 | /**
6 | * @typedef { import('mongodb').TopologyDescription } TopologyDescription
7 | */
8 |
9 | /**
10 | * Checks if topologyDescription contains servers connected to an atlas instance
11 | *
12 | * @param {TopologyDescription} topologyDescription
13 | * @returns {boolean}
14 | */
15 | module.exports = function isAtlas(topologyDescription) {
16 | if (getConstructorName(topologyDescription) !== 'TopologyDescription') {
17 | return false;
18 | }
19 |
20 | if (topologyDescription.servers.size === 0) {
21 | return false;
22 | }
23 |
24 | for (const server of topologyDescription.servers.values()) {
25 | if (server.host.endsWith('.mongodb.net') === false || server.port !== 27017) {
26 | return false;
27 | }
28 | }
29 |
30 | return true;
31 | };
32 |
--------------------------------------------------------------------------------
/docs/customschematypes.md:
--------------------------------------------------------------------------------
1 | # Custom Schema Types
2 |
3 | ## Creating a Basic Custom Schema Type
4 |
5 | *New in Mongoose 4.4.0:* Mongoose supports custom types. Before you
6 | reach for a custom type, however, know that a custom type is overkill
7 | for most use cases. You can do most basic tasks with
8 | [custom getters/setters](http://mongoosejs.com/docs/2.7.x/docs/getters-setters.html),
9 | [virtuals](http://mongoosejs.com/docs/guide.html#virtuals), and
10 | [single embedded docs](http://mongoosejs.com/docs/subdocs.html#single-embedded).
11 |
12 | Let's take a look at an example of a basic schema type: a 1-byte integer.
13 | To create a new schema type, you need to inherit from `mongoose.SchemaType`
14 | and add the corresponding property to `mongoose.Schema.Types`. The one
15 | method you need to implement is the `cast()` method.
16 |
17 | ```acquit
18 | [require:Creating a Basic Custom Schema Type]
19 | ```
20 |
--------------------------------------------------------------------------------
/lib/helpers/populate/removeDeselectedForeignField.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const get = require('../get');
4 | const mpath = require('mpath');
5 | const parseProjection = require('../projection/parseProjection');
6 |
7 | /*!
8 | * ignore
9 | */
10 |
11 | module.exports = function removeDeselectedForeignField(foreignFields, options, docs) {
12 | const projection = parseProjection(get(options, 'select', null), true) ||
13 | parseProjection(get(options, 'options.select', null), true);
14 |
15 | if (projection == null) {
16 | return;
17 | }
18 | for (const foreignField of foreignFields) {
19 | if (!Object.hasOwn(projection, '-' + foreignField)) {
20 | continue;
21 | }
22 |
23 | for (const val of docs) {
24 | if (val.$__ != null) {
25 | mpath.unset(foreignField, val._doc);
26 | } else {
27 | mpath.unset(foreignField, val);
28 | }
29 | }
30 | }
31 | };
32 |
--------------------------------------------------------------------------------
/tools/repl.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | run().catch(error => {
4 | console.error(error);
5 | process.exit(-1);
6 | });
7 |
8 | async function run() {
9 | const ReplSet = require('mongodb-memory-server').MongoMemoryReplSet;
10 |
11 | // Create new instance
12 | const replSet = new ReplSet({
13 | binary: {
14 | version: process.argv[2]
15 | },
16 | instanceOpts: [
17 | // Set the expiry job in MongoDB to run every second
18 | {
19 | port: 27017,
20 | args: ['--setParameter', 'ttlMonitorSleepSecs=1']
21 | }
22 | ],
23 | dbName: 'mongoose_test',
24 | replSet: {
25 | name: 'rs0',
26 | count: 2,
27 | storageEngine: 'wiredTiger'
28 | }
29 | });
30 |
31 | await replSet.start();
32 | await replSet.waitUntilRunning();
33 | console.log('MongoDB-ReplicaSet is now running.');
34 | console.log(replSet.getUri('mongoose_test'));
35 | }
36 |
--------------------------------------------------------------------------------
/docs/images/favicon/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "App",
3 | "icons": [
4 | {
5 | "src": "\/android-icon-36x36.png",
6 | "sizes": "36x36",
7 | "type": "image\/png",
8 | "density": "0.75"
9 | },
10 | {
11 | "src": "\/android-icon-48x48.png",
12 | "sizes": "48x48",
13 | "type": "image\/png",
14 | "density": "1.0"
15 | },
16 | {
17 | "src": "\/android-icon-72x72.png",
18 | "sizes": "72x72",
19 | "type": "image\/png",
20 | "density": "1.5"
21 | },
22 | {
23 | "src": "\/android-icon-96x96.png",
24 | "sizes": "96x96",
25 | "type": "image\/png",
26 | "density": "2.0"
27 | },
28 | {
29 | "src": "\/android-icon-144x144.png",
30 | "sizes": "144x144",
31 | "type": "image\/png",
32 | "density": "3.0"
33 | },
34 | {
35 | "src": "\/android-icon-192x192.png",
36 | "sizes": "192x192",
37 | "type": "image\/png",
38 | "density": "4.0"
39 | }
40 | ]
41 | }
--------------------------------------------------------------------------------
/lib/helpers/arrayDepth.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = arrayDepth;
4 |
5 | function arrayDepth(arr) {
6 | if (!Array.isArray(arr)) {
7 | return { min: 0, max: 0, containsNonArrayItem: true };
8 | }
9 | if (arr.length === 0) {
10 | return { min: 1, max: 1, containsNonArrayItem: false };
11 | }
12 | if (arr.length === 1 && !Array.isArray(arr[0])) {
13 | return { min: 1, max: 1, containsNonArrayItem: false };
14 | }
15 |
16 | const res = arrayDepth(arr[0]);
17 |
18 | for (let i = 1; i < arr.length; ++i) {
19 | const _res = arrayDepth(arr[i]);
20 | if (_res.min < res.min) {
21 | res.min = _res.min;
22 | }
23 | if (_res.max > res.max) {
24 | res.max = _res.max;
25 | }
26 | res.containsNonArrayItem = res.containsNonArrayItem || _res.containsNonArrayItem;
27 | }
28 |
29 | res.min = res.min + 1;
30 | res.max = res.max + 1;
31 |
32 | return res;
33 | }
34 |
--------------------------------------------------------------------------------
/lib/helpers/update/updatedPathsByArrayFilter.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const modifiedPaths = require('./modifiedPaths');
4 |
5 | module.exports = function updatedPathsByArrayFilter(update) {
6 | if (update == null) {
7 | return {};
8 | }
9 | const updatedPaths = modifiedPaths(update);
10 |
11 | return Object.keys(updatedPaths).reduce((cur, path) => {
12 | const matches = path.match(/\$\[[^\]]+\]/g);
13 | if (matches == null) {
14 | return cur;
15 | }
16 | for (const match of matches) {
17 | const firstMatch = path.indexOf(match);
18 | if (firstMatch !== path.lastIndexOf(match)) {
19 | throw new Error(`Path '${path}' contains the same array filter multiple times`);
20 | }
21 | cur[match.substring(2, match.length - 1)] = path.
22 | substring(0, firstMatch - 1).
23 | replace(/\$\[[^\]]+\]/g, '0');
24 | }
25 | return cur;
26 | }, {});
27 | };
28 |
--------------------------------------------------------------------------------
/lib/helpers/populate/lookupLocalFields.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = function lookupLocalFields(cur, path, val) {
4 | if (cur == null) {
5 | return cur;
6 | }
7 |
8 | if (cur._doc != null) {
9 | cur = cur._doc;
10 | }
11 |
12 | if (arguments.length >= 3) {
13 | if (typeof cur !== 'object') {
14 | return void 0;
15 | }
16 | if (val === void 0) {
17 | return void 0;
18 | }
19 | if (cur instanceof Map) {
20 | cur.set(path, val);
21 | } else {
22 | cur[path] = val;
23 | }
24 | return val;
25 | }
26 |
27 |
28 | // Support populating paths under maps using `map.$*.subpath`
29 | if (path === '$*') {
30 | return cur instanceof Map ?
31 | Array.from(cur.values()) :
32 | Object.keys(cur).map(key => cur[key]);
33 | }
34 |
35 | if (cur instanceof Map) {
36 | return cur.get(path);
37 | }
38 |
39 | return cur[path];
40 | };
41 |
--------------------------------------------------------------------------------
/docs/tutorials/custom-casting.md:
--------------------------------------------------------------------------------
1 | # Custom Casting
2 |
3 | [Mongoose 5.4.0](https://github.com/Automattic/mongoose/blob/master/CHANGELOG.md#540--2018-12-14) introduced [several ways to configure SchemaTypes globally](http://thecodebarbarian.com/whats-new-in-mongoose-54-global-schematype-configuration).
4 | One of these new features is the [`SchemaType.cast()` function](../api/schematype.html#schematype_SchemaType-cast), which enables you to override Mongoose's built-in casting.
5 |
6 | For example, by default Mongoose will throw an error if you attempt to cast
7 | a string that contains a Japanese numeral to a number.
8 |
9 | ```acquit
10 | [require:custom casting.*casting error]
11 | ```
12 |
13 | You can overwrite the default casting function for numbers to allow converting
14 | the string that contains the Japanese numeral "2" to a number as shown below.
15 |
16 | ```acquit
17 | [require:custom casting.*casting override]
18 | ```
19 |
--------------------------------------------------------------------------------
/lib/options/schemaBufferOptions.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const SchemaTypeOptions = require('./schemaTypeOptions');
4 |
5 | /**
6 | * The options defined on a Buffer schematype.
7 | *
8 | * #### Example:
9 | *
10 | * const schema = new Schema({ bitmap: Buffer });
11 | * schema.path('bitmap').options; // SchemaBufferOptions instance
12 | *
13 | * @api public
14 | * @inherits SchemaTypeOptions
15 | * @constructor SchemaBufferOptions
16 | */
17 |
18 | class SchemaBufferOptions extends SchemaTypeOptions {}
19 |
20 | const opts = require('./propertyOptions');
21 |
22 | /**
23 | * Set the default subtype for this buffer.
24 | *
25 | * @api public
26 | * @property subtype
27 | * @memberOf SchemaBufferOptions
28 | * @type {Number}
29 | * @instance
30 | */
31 |
32 | Object.defineProperty(SchemaBufferOptions.prototype, 'subtype', opts);
33 |
34 | /*!
35 | * ignore
36 | */
37 |
38 | module.exports = SchemaBufferOptions;
39 |
--------------------------------------------------------------------------------
/lib/error/version.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /*!
4 | * Module dependencies.
5 | */
6 |
7 | const MongooseError = require('./mongooseError');
8 |
9 | /**
10 | * Version Error constructor.
11 | *
12 | * @param {Document} doc
13 | * @param {Number} currentVersion
14 | * @param {Array} modifiedPaths
15 | * @api private
16 | */
17 |
18 | class VersionError extends MongooseError {
19 |
20 | constructor(doc, currentVersion, modifiedPaths) {
21 | const modifiedPathsStr = modifiedPaths.join(', ');
22 | super('No matching document found for id "' + doc._doc._id +
23 | '" version ' + currentVersion + ' modifiedPaths "' + modifiedPathsStr + '"');
24 | this.version = currentVersion;
25 | this.modifiedPaths = modifiedPaths;
26 | }
27 | }
28 |
29 |
30 | Object.defineProperty(VersionError.prototype, 'name', {
31 | value: 'VersionError'
32 | });
33 |
34 | /*!
35 | * exports
36 | */
37 |
38 | module.exports = VersionError;
39 |
--------------------------------------------------------------------------------
/lib/validOptions.js:
--------------------------------------------------------------------------------
1 |
2 | /*!
3 | * Valid mongoose options
4 | */
5 |
6 | 'use strict';
7 |
8 | const VALID_OPTIONS = Object.freeze([
9 | 'allowDiskUse',
10 | 'applyPluginsToChildSchemas',
11 | 'applyPluginsToDiscriminators',
12 | 'autoCreate',
13 | 'autoIndex',
14 | 'autoSearchIndex',
15 | 'bufferCommands',
16 | 'bufferTimeoutMS',
17 | 'cloneSchemas',
18 | 'createInitialConnection',
19 | 'debug',
20 | 'forceRepopulate',
21 | 'id',
22 | 'maxTimeMS',
23 | 'objectIdGetter',
24 | 'overwriteModels',
25 | 'returnOriginal',
26 | 'runValidators',
27 | 'sanitizeFilter',
28 | 'sanitizeProjection',
29 | 'selectPopulatedPaths',
30 | 'setDefaultsOnInsert',
31 | 'strict',
32 | 'strictPopulate',
33 | 'strictQuery',
34 | 'timestamps.createdAt.immutable',
35 | 'toJSON',
36 | 'toObject',
37 | 'transactionAsyncLocalStorage',
38 | 'translateAliases',
39 | 'updatePipeline'
40 | ]);
41 |
42 | module.exports = VALID_OPTIONS;
43 |
--------------------------------------------------------------------------------
/.github/workflows/benchmark.yml:
--------------------------------------------------------------------------------
1 | name: TypeScript Benchmark
2 | on:
3 | pull_request:
4 | paths:
5 | - ".github/workflows/benchmark.yml"
6 | - "package.json"
7 | - "types/**"
8 | - "benchmarks/typescript/**"
9 | push:
10 | branches:
11 | - master
12 | paths:
13 | - ".github/workflows/benchmark.yml"
14 | - "package.json"
15 | - "types/**"
16 | - "benchmarks/typescript/**"
17 | permissions:
18 | contents: read
19 |
20 | jobs:
21 | typescript:
22 | runs-on: ubuntu-22.04
23 | name: Benchmark TypeScript Types
24 | steps:
25 | - uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
26 | - name: Setup node
27 | uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
28 | with:
29 | node-version: 22
30 |
31 | - run: npm install
32 |
33 | - run: node ./scripts/create-tarball.js
34 |
35 | - run: npm run ts-benchmark
36 |
--------------------------------------------------------------------------------
/lib/helpers/query/applyGlobalOption.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const utils = require('../../utils');
4 |
5 | function applyGlobalMaxTimeMS(options, connectionOptions, baseOptions) {
6 | applyGlobalOption(options, connectionOptions, baseOptions, 'maxTimeMS');
7 | }
8 |
9 | function applyGlobalDiskUse(options, connectionOptions, baseOptions) {
10 | applyGlobalOption(options, connectionOptions, baseOptions, 'allowDiskUse');
11 | }
12 |
13 | module.exports = {
14 | applyGlobalMaxTimeMS,
15 | applyGlobalDiskUse
16 | };
17 |
18 |
19 | function applyGlobalOption(options, connectionOptions, baseOptions, optionName) {
20 | if (utils.hasUserDefinedProperty(options, optionName)) {
21 | return;
22 | }
23 |
24 | if (utils.hasUserDefinedProperty(connectionOptions, optionName)) {
25 | options[optionName] = connectionOptions[optionName];
26 | } else if (utils.hasUserDefinedProperty(baseOptions, optionName)) {
27 | options[optionName] = baseOptions[optionName];
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/lib/helpers/update/decorateUpdateWithVersionKey.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * Decorate the update with a version key, if necessary
5 | * @api private
6 | */
7 |
8 | module.exports = function decorateUpdateWithVersionKey(update, options, versionKey) {
9 | if (!versionKey || !(options && options.upsert || false)) {
10 | return;
11 | }
12 |
13 | if (options.overwrite) {
14 | if (!hasKey(update, versionKey)) {
15 | update[versionKey] = 0;
16 | }
17 | } else if (
18 | !hasKey(update, versionKey) &&
19 | !hasKey(update?.$set, versionKey) &&
20 | !hasKey(update?.$inc, versionKey) &&
21 | !hasKey(update?.$setOnInsert, versionKey)
22 | ) {
23 | if (!update.$setOnInsert) {
24 | update.$setOnInsert = {};
25 | }
26 | update.$setOnInsert[versionKey] = 0;
27 | }
28 | };
29 |
30 | function hasKey(obj, key) {
31 | if (obj == null || typeof obj !== 'object') {
32 | return false;
33 | }
34 | return Object.hasOwn(obj, key);
35 | }
36 |
--------------------------------------------------------------------------------
/test/deno.mjs:
--------------------------------------------------------------------------------
1 | import { createRequire } from 'node:module';
2 | import process from 'node:process';
3 | import { resolve } from 'node:path';
4 | import { fileURLToPath } from 'node:url';
5 |
6 | import { spawn } from 'node:child_process';
7 |
8 | Error.stackTraceLimit = 100;
9 |
10 | const require = createRequire(import.meta.url);
11 |
12 | const fixtures = require('./mocha-fixtures.js');
13 |
14 | await fixtures.mochaGlobalSetup();
15 |
16 | const child_args = [
17 | ...Deno.args,
18 | resolve(fileURLToPath(import.meta.url), '../deno_mocha.mjs')
19 | ];
20 |
21 | const child = spawn(process.execPath, child_args, { stdio: 'inherit' });
22 |
23 | child.on('exit', (code, signal) => {
24 | signal ? doExit(-100) : doExit(code);
25 | });
26 |
27 | Deno.addSignalListener('SIGINT', () => {
28 | console.log('SIGINT');
29 | child.kill('SIGINT');
30 | doExit(-2);
31 | });
32 |
33 | async function doExit(code) {
34 | await fixtures.mochaGlobalTeardown();
35 | Deno.exit(code);
36 | }
37 |
--------------------------------------------------------------------------------
/lib/types/objectid.js:
--------------------------------------------------------------------------------
1 | /**
2 | * ObjectId type constructor
3 | *
4 | * #### Example:
5 | *
6 | * const id = new mongoose.Types.ObjectId;
7 | *
8 | * @constructor ObjectId
9 | */
10 |
11 | 'use strict';
12 |
13 | const ObjectId = require('mongodb/lib/bson').ObjectId;
14 | const objectIdSymbol = require('../helpers/symbols').objectIdSymbol;
15 |
16 | /**
17 | * Getter for convenience with populate, see gh-6115
18 | * @api private
19 | */
20 |
21 | Object.defineProperty(ObjectId.prototype, '_id', {
22 | enumerable: false,
23 | configurable: true,
24 | get: function() {
25 | return this;
26 | }
27 | });
28 |
29 | /*!
30 | * Convenience `valueOf()` to allow comparing ObjectIds using double equals re: gh-7299
31 | */
32 |
33 | if (!Object.hasOwn(ObjectId.prototype, 'valueOf')) {
34 | ObjectId.prototype.valueOf = function objectIdValueOf() {
35 | return this.toString();
36 | };
37 | }
38 |
39 | ObjectId.prototype[objectIdSymbol] = true;
40 |
41 | module.exports = ObjectId;
42 |
--------------------------------------------------------------------------------
/test/helpers/update.applyTimestampsToChildren.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Schema = require('../../lib/schema');
4 | const applyTimestampsToChildren = require('../../lib/helpers/update/applyTimestampsToChildren');
5 | const assert = require('assert');
6 |
7 | describe('applyTimestampsToChildren', function() {
8 | it('applies timestamps to nested subdocs within a $push (gh-11775)', function() {
9 | const update = {
10 | $push: {
11 | l1: {
12 | l2: {
13 | prop: 'test'
14 | }
15 | }
16 | }
17 | };
18 | const now = new Date('2016-01-01');
19 | const schema = new Schema({
20 | l1: [new Schema({ l2: new Schema({ prop: String }, { timestamps: true }) }, { timestamps: true })]
21 | });
22 | applyTimestampsToChildren(now, update, schema);
23 |
24 | assert.equal(update.$push.l1.l2.createdAt.valueOf(), now.valueOf());
25 | assert.equal(update.$push.l1.l2.updatedAt.valueOf(), now.valueOf());
26 | });
27 | });
28 |
--------------------------------------------------------------------------------
/lib/cast/boolean.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const CastError = require('../error/cast');
4 |
5 | /**
6 | * Given a value, cast it to a boolean, or throw a `CastError` if the value
7 | * cannot be casted. `null` and `undefined` are considered valid.
8 | *
9 | * @param {Any} value
10 | * @param {String} [path] optional the path to set on the CastError
11 | * @return {Boolean|null|undefined}
12 | * @throws {CastError} if `value` is not one of the allowed values
13 | * @api private
14 | */
15 |
16 | module.exports = function castBoolean(value, path) {
17 | if (module.exports.convertToTrue.has(value)) {
18 | return true;
19 | }
20 | if (module.exports.convertToFalse.has(value)) {
21 | return false;
22 | }
23 |
24 | if (value == null) {
25 | return value;
26 | }
27 |
28 | throw new CastError('boolean', value, path);
29 | };
30 |
31 | module.exports.convertToTrue = new Set([true, 'true', 1, '1', 'yes']);
32 | module.exports.convertToFalse = new Set([false, 'false', 0, '0', 'no']);
33 |
--------------------------------------------------------------------------------
/lib/helpers/projection/isPathExcluded.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const isDefiningProjection = require('./isDefiningProjection');
4 |
5 | /**
6 | * Determines if `path` is excluded by `projection`
7 | *
8 | * @param {Object} projection
9 | * @param {String} path
10 | * @return {Boolean}
11 | * @api private
12 | */
13 |
14 | module.exports = function isPathExcluded(projection, path) {
15 | if (projection == null) {
16 | return false;
17 | }
18 |
19 | if (path === '_id') {
20 | return projection._id === 0;
21 | }
22 |
23 | const paths = Object.keys(projection);
24 | let type = null;
25 |
26 | for (const _path of paths) {
27 | if (isDefiningProjection(projection[_path])) {
28 | type = projection[path] === 1 ? 'inclusive' : 'exclusive';
29 | break;
30 | }
31 | }
32 |
33 | if (type === 'inclusive') {
34 | return projection[path] !== 1;
35 | }
36 | if (type === 'exclusive') {
37 | return projection[path] === 0;
38 | }
39 | return false;
40 | };
41 |
--------------------------------------------------------------------------------
/lib/options/populateOptions.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const clone = require('../helpers/clone');
4 |
5 | class PopulateOptions {
6 | constructor(obj) {
7 | this._docs = {};
8 | this._childDocs = [];
9 |
10 | if (obj == null) {
11 | return;
12 | }
13 | obj = clone(obj);
14 | Object.assign(this, obj);
15 | if (typeof obj.subPopulate === 'object') {
16 | this.populate = obj.subPopulate;
17 | }
18 |
19 |
20 | if (obj.perDocumentLimit != null && obj.limit != null) {
21 | throw new Error('Can not use `limit` and `perDocumentLimit` at the same time. Path: `' + obj.path + '`.');
22 | }
23 | }
24 | }
25 |
26 | /**
27 | * The connection used to look up models by name. If not specified, Mongoose
28 | * will default to using the connection associated with the model in
29 | * `PopulateOptions#model`.
30 | *
31 | * @memberOf PopulateOptions
32 | * @property {Connection} connection
33 | * @api public
34 | */
35 |
36 | module.exports = PopulateOptions;
37 |
--------------------------------------------------------------------------------
/lib/schema/index.js:
--------------------------------------------------------------------------------
1 |
2 | /*!
3 | * Module exports.
4 | */
5 |
6 | 'use strict';
7 |
8 | exports.Array = require('./array');
9 | exports.BigInt = require('./bigint');
10 | exports.Boolean = require('./boolean');
11 | exports.Buffer = require('./buffer');
12 | exports.Date = require('./date');
13 | exports.Decimal128 = exports.Decimal = require('./decimal128');
14 | exports.DocumentArray = require('./documentArray');
15 | exports.Double = require('./double');
16 | exports.Int32 = require('./int32');
17 | exports.Map = require('./map');
18 | exports.Mixed = require('./mixed');
19 | exports.Number = require('./number');
20 | exports.ObjectId = require('./objectId');
21 | exports.String = require('./string');
22 | exports.Subdocument = require('./subdocument');
23 | exports.UUID = require('./uuid');
24 | exports.Union = require('./union');
25 |
26 | // alias
27 |
28 | exports.Oid = exports.ObjectId;
29 | exports.Object = exports.Mixed;
30 | exports.Bool = exports.Boolean;
31 | exports.ObjectID = exports.ObjectId;
32 |
--------------------------------------------------------------------------------
/lib/cast/int32.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const isBsonType = require('../helpers/isBsonType');
4 | const assert = require('assert');
5 |
6 | /**
7 | * Given a value, cast it to a Int32, or throw an `Error` if the value
8 | * cannot be casted. `null` and `undefined` are considered valid.
9 | *
10 | * @param {Any} value
11 | * @return {Number}
12 | * @throws {Error} if `value` does not represent an integer, or is outside the bounds of an 32-bit integer.
13 | * @api private
14 | */
15 |
16 | module.exports = function castInt32(val) {
17 | if (val == null) {
18 | return val;
19 | }
20 | if (val === '') {
21 | return null;
22 | }
23 |
24 | const coercedVal = isBsonType(val, 'Long') ? val.toNumber() : Number(val);
25 |
26 | const INT32_MAX = 0x7FFFFFFF;
27 | const INT32_MIN = -0x80000000;
28 |
29 | if (coercedVal === (coercedVal | 0) &&
30 | coercedVal >= INT32_MIN &&
31 | coercedVal <= INT32_MAX
32 | ) {
33 | return coercedVal;
34 | }
35 | assert.ok(false);
36 | };
37 |
--------------------------------------------------------------------------------
/lib/helpers/update/modifiedPaths.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const _modifiedPaths = require('../common').modifiedPaths;
4 |
5 | /**
6 | * Given an update document with potential update operators (`$set`, etc.)
7 | * returns an object whose keys are the directly modified paths.
8 | *
9 | * If there are any top-level keys that don't start with `$`, we assume those
10 | * will get wrapped in a `$set`. The Mongoose Query is responsible for wrapping
11 | * top-level keys in `$set`.
12 | *
13 | * @param {Object} update
14 | * @return {Object} modified
15 | */
16 |
17 | module.exports = function modifiedPaths(update) {
18 | const keys = Object.keys(update);
19 | const res = {};
20 |
21 | const withoutDollarKeys = {};
22 | for (const key of keys) {
23 | if (key.startsWith('$')) {
24 | _modifiedPaths(update[key], '', res);
25 | continue;
26 | }
27 | withoutDollarKeys[key] = update[key];
28 | }
29 |
30 | _modifiedPaths(withoutDollarKeys, '', res);
31 |
32 | return res;
33 | };
34 |
--------------------------------------------------------------------------------
/types/virtuals.d.ts:
--------------------------------------------------------------------------------
1 | declare module 'mongoose' {
2 | type VirtualPathFunctions = {
3 | get?: TVirtualPathFN;
4 | set?: TVirtualPathFN;
5 | options?: VirtualTypeOptions, DocType>;
6 | };
7 |
8 | type TVirtualPathFN =
9 | >(this: Document & DocType, value: PathType, virtual: VirtualType, doc: Document & DocType) => TReturn;
10 |
11 | type SchemaOptionsVirtualsPropertyType, TInstanceMethods = {}> = {
12 | [K in keyof VirtualPaths]: VirtualPathFunctions extends true ? DocType : any, VirtualPaths[K], TInstanceMethods>
13 | };
14 | }
15 |
--------------------------------------------------------------------------------
/docs/js/navbar-search.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | (function() {
3 | const versionFromUrl = window.location.pathname.match(/^\/docs\/(\d+\.x)/);
4 | const version = versionFromUrl ? versionFromUrl[1] : null;
5 |
6 | const searchPrefix = versionFromUrl ? '/docs/' + version + '/docs/' : '/docs/';
7 |
8 | // dont use nav-bar search for search site, let the search site handle that
9 | if (/\/search(:?\.html)?$/i.test(window.location.pathname)) {
10 | return;
11 | }
12 |
13 | document.getElementById('search-button-nav').onclick = function() {
14 | const q = document.getElementById('search-input-nav').value;
15 | window.location.href = searchPrefix + 'search.html?q=' + encodeURIComponent(q);
16 | };
17 |
18 | document.getElementById('search-input-nav').onkeyup = function(ev) {
19 | if (ev.keyCode === 13) {
20 | const q = document.getElementById('search-input-nav').value;
21 | window.location.href = searchPrefix + 'search.html?q=' + encodeURIComponent(q);
22 | }
23 | };
24 | })();
25 |
--------------------------------------------------------------------------------
/test/schema.string.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const start = require('./common');
4 |
5 | const assert = require('assert');
6 |
7 | const mongoose = start.mongoose;
8 | const Schema = mongoose.Schema;
9 |
10 | describe('SchemaString', function() {
11 | let M;
12 |
13 | before(function() {
14 | const schema = new Schema({ x: { type: String, match: /abc/g } });
15 | mongoose.deleteModel(/Test/);
16 | M = mongoose.model('Test', schema);
17 | });
18 |
19 | it('works when RegExp has global flag set (gh-9287)', function() {
20 | const doc = new M({ x: 'abc' });
21 | assert.ifError(doc.validateSync());
22 | assert.ifError(doc.validateSync());
23 | });
24 |
25 | it('regex validator works with validate() (gh-15380)', async function() {
26 | const schema = new Schema({ x: { type: String, validate: /abc/g } });
27 | mongoose.deleteModel(/Test/);
28 | M = mongoose.model('Test', schema);
29 |
30 | const doc = new M({ x: 'abc' });
31 | await doc.validate();
32 | });
33 | });
34 |
--------------------------------------------------------------------------------
/lib/helpers/document/handleSpreadDoc.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const utils = require('../../utils');
4 |
5 | const keysToSkip = new Set(['__index', '__parentArray', '_doc']);
6 |
7 | /**
8 | * Using spread operator on a Mongoose document gives you a
9 | * POJO that has a tendency to cause infinite recursion. So
10 | * we use this function on `set()` to prevent that.
11 | */
12 |
13 | module.exports = function handleSpreadDoc(v, includeExtraKeys) {
14 | if (utils.isPOJO(v) && v.$__ != null && v._doc != null) {
15 | if (includeExtraKeys) {
16 | const extraKeys = {};
17 | for (const key of Object.keys(v)) {
18 | if (typeof key === 'symbol') {
19 | continue;
20 | }
21 | if (key[0] === '$') {
22 | continue;
23 | }
24 | if (keysToSkip.has(key)) {
25 | continue;
26 | }
27 | extraKeys[key] = v[key];
28 | }
29 | return { ...v._doc, ...extraKeys };
30 | }
31 | return v._doc;
32 | }
33 |
34 | return v;
35 | };
36 |
--------------------------------------------------------------------------------
/test/helpers/indexes.isIndexSpecEqual.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const assert = require('assert');
4 | const isIndexSpecEqual = require('../../lib/helpers/indexes/isIndexSpecEqual');
5 |
6 | describe('isIndexSpecEqual', function() {
7 | it('should return true for equal index specifications', () => {
8 | const spec1 = { name: 1, age: -1 };
9 | const spec2 = { name: 1, age: -1 };
10 | const result = isIndexSpecEqual(spec1, spec2);
11 | assert.strictEqual(result, true);
12 | });
13 |
14 | it('should return false for different key order', () => {
15 | const spec1 = { name: 1, age: -1 };
16 | const spec2 = { age: -1, name: 1 };
17 | const result = isIndexSpecEqual(spec1, spec2);
18 | assert.strictEqual(result, false);
19 | });
20 |
21 | it('should return false for different index keys', () => {
22 | const spec1 = { name: 1, age: -1 };
23 | const spec2 = { name: 1, dob: -1 };
24 | const result = isIndexSpecEqual(spec1, spec2);
25 | assert.strictEqual(result, false);
26 | });
27 | });
28 |
--------------------------------------------------------------------------------
/lib/helpers/timestamps/setDocumentTimestamps.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = function setDocumentTimestamps(doc, timestampOption, currentTime, createdAt, updatedAt) {
4 | const skipUpdatedAt = timestampOption != null && timestampOption.updatedAt === false;
5 | const skipCreatedAt = timestampOption != null && timestampOption.createdAt === false;
6 |
7 | const defaultTimestamp = currentTime != null ?
8 | currentTime() :
9 | doc.ownerDocument().constructor.base.now();
10 |
11 | if (!skipCreatedAt &&
12 | (doc.isNew || doc.$isSubdocument) &&
13 | createdAt &&
14 | !doc.$__getValue(createdAt) &&
15 | doc.$__isSelected(createdAt)) {
16 | doc.$set(createdAt, defaultTimestamp, undefined, { overwriteImmutable: true });
17 | }
18 |
19 | if (!skipUpdatedAt && updatedAt && (doc.isNew || doc.$isModified())) {
20 | let ts = defaultTimestamp;
21 | if (doc.isNew && createdAt != null) {
22 | ts = doc.$__getValue(createdAt);
23 | }
24 | doc.$set(updatedAt, ts);
25 | }
26 | };
27 |
--------------------------------------------------------------------------------
/.github/workflows/tidelift-alignment.yml:
--------------------------------------------------------------------------------
1 | name: Tidelift Alignment
2 | on:
3 | push:
4 | paths:
5 | - '.github/workflows/tidelift-alignment.yml'
6 | - 'package.json'
7 |
8 | permissions:
9 | contents: read
10 |
11 | jobs:
12 | build:
13 | name: Run Tidelift to ensure approved open source packages are in use
14 | runs-on: ubuntu-latest
15 | if: github.repository == 'Automattic/mongoose'
16 | steps:
17 | - name: Checkout
18 | uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
19 | - name: Setup node
20 | uses: actions/setup-node@2028fbc5c25fe9cf00d9f06a71cc4710d4507903 # v6.0.0
21 | with:
22 | node-version: 22
23 | - name: Alignment
24 | uses: tidelift/alignment-action@8d7700fe795fc01179c1f9fa05b72a089873027d # main
25 | env:
26 | TIDELIFT_API_KEY: ${{ secrets.TIDELIFT_API_KEY }}
27 | TIDELIFT_ORGANIZATION: ${{ secrets.TIDELIFT_ORGANIZATION }}
28 | TIDELIFT_PROJECT: ${{ secrets.TIDELIFT_PROJECT }}
29 |
--------------------------------------------------------------------------------
/lib/helpers/printJestWarning.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const utils = require('../utils');
4 |
5 | if (typeof jest !== 'undefined' && !process.env.SUPPRESS_JEST_WARNINGS) {
6 | if (typeof window !== 'undefined') {
7 | utils.warn('Mongoose: looks like you\'re trying to test a Mongoose app ' +
8 | 'with Jest\'s default jsdom test environment. Please make sure you read ' +
9 | 'Mongoose\'s docs on configuring Jest to test Node.js apps: ' +
10 | 'https://mongoosejs.com/docs/jest.html. Set the SUPPRESS_JEST_WARNINGS to true ' +
11 | 'to hide this warning.');
12 | }
13 |
14 | if (setTimeout.clock != null && typeof setTimeout.clock.Date === 'function') {
15 | utils.warn('Mongoose: looks like you\'re trying to test a Mongoose app ' +
16 | 'with Jest\'s mock timers enabled. Please make sure you read ' +
17 | 'Mongoose\'s docs on configuring Jest to test Node.js apps: ' +
18 | 'https://mongoosejs.com/docs/jest.html. Set the SUPPRESS_JEST_WARNINGS to true ' +
19 | 'to hide this warning.');
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/lib/helpers/projection/isExclusive.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const isDefiningProjection = require('./isDefiningProjection');
4 | const isPOJO = require('../isPOJO');
5 |
6 | /*!
7 | * ignore
8 | */
9 |
10 | module.exports = function isExclusive(projection) {
11 | if (projection == null) {
12 | return null;
13 | }
14 |
15 | const keys = Object.keys(projection);
16 | let exclude = null;
17 |
18 | if (keys.length === 1 && keys[0] === '_id') {
19 | exclude = !projection._id;
20 | } else {
21 | for (let ki = 0; ki < keys.length; ++ki) {
22 | // Does this projection explicitly define inclusion/exclusion?
23 | // Explicitly avoid `$meta` and `$slice`
24 | const key = keys[ki];
25 | if (key !== '_id' && isDefiningProjection(projection[key])) {
26 | exclude = isPOJO(projection[key]) ?
27 | (isExclusive(projection[key]) ?? exclude) :
28 | !projection[key];
29 | if (exclude != null) {
30 | break;
31 | }
32 | }
33 | }
34 | }
35 |
36 | return exclude;
37 | };
38 |
--------------------------------------------------------------------------------
/lib/helpers/query/sanitizeFilter.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const hasDollarKeys = require('./hasDollarKeys');
4 | const { trustedSymbol } = require('./trusted');
5 |
6 | module.exports = function sanitizeFilter(filter) {
7 | if (filter == null || typeof filter !== 'object') {
8 | return filter;
9 | }
10 | if (Array.isArray(filter)) {
11 | for (const subfilter of filter) {
12 | sanitizeFilter(subfilter);
13 | }
14 | return filter;
15 | }
16 |
17 | const filterKeys = Object.keys(filter);
18 | for (const key of filterKeys) {
19 | const value = filter[key];
20 | if (value != null && value[trustedSymbol]) {
21 | continue;
22 | }
23 | if (key === '$and' || key === '$or') {
24 | sanitizeFilter(value);
25 | continue;
26 | }
27 |
28 | if (hasDollarKeys(value)) {
29 | const keys = Object.keys(value);
30 | if (keys.length === 1 && keys[0] === '$eq') {
31 | continue;
32 | }
33 | filter[key] = { $eq: filter[key] };
34 | }
35 | }
36 |
37 | return filter;
38 | };
39 |
--------------------------------------------------------------------------------
/test/types/utility.test.ts:
--------------------------------------------------------------------------------
1 | import { MergeType, WithTimestamps } from 'mongoose';
2 | import { expectType } from 'tsd';
3 |
4 | type A = { a: string, c: number };
5 | type B = { a: number, b: string };
6 |
7 | expectType({} as MergeType['a']);
8 | expectType({} as MergeType['b']);
9 | expectType({} as MergeType['c']);
10 |
11 | expectType({} as MergeType['a']);
12 | expectType({} as MergeType['b']);
13 | expectType({} as MergeType['c']);
14 |
15 | type C = WithTimestamps<{ a: string; b: string }>;
16 | expectType({} as C['a']);
17 | expectType({} as C['b']);
18 | expectType({} as C['createdAt']);
19 | expectType({} as C['updatedAt']);
20 |
21 | type D = WithTimestamps<
22 | { a: string; b: string },
23 | {
24 | createdAt: 'created';
25 | updatedAt: 'modified';
26 | }
27 | >;
28 | expectType({} as D['a']);
29 | expectType({} as D['b']);
30 | expectType({} as D['created']);
31 | expectType({} as D['modified']);
32 |
--------------------------------------------------------------------------------
/docs/source/utils.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 | const fs = require('fs');
3 |
4 | /**
5 | * @typedef {import("./index").DocsOptions} DocsOptions
6 | */
7 |
8 | /**
9 | * Map sub-directories with custom options
10 | * @param {String} subDoc Path to the subdoc, like "tutorials" (no beginning or ending slash)
11 | * @param {DocsOptions} options Options applied to all files in the subdoc (title gets appended to provided title)
12 | * @param {Object} exportsObj The "module.exports" object to apply changes to
13 | */
14 | function mapSubDoc(subDoc, options, exportsObj) {
15 | const dirName = `docs/${subDoc}`;
16 |
17 | const files = fs.readdirSync(dirName).filter(file => file.endsWith('.md'));
18 |
19 | files.forEach((filename) => {
20 | const content = fs.readFileSync(`${dirName}/${filename}`, 'utf8');
21 | exportsObj[`${dirName}/${filename}`] = {
22 | ...options,
23 | title: `${options.title} ${content.split('\n')[0].replace(/^#+/, '').trim()}`
24 | };
25 | });
26 | }
27 |
28 | module.exports = mapSubDoc;
29 | module.exports.mapSubDoc = mapSubDoc;
30 |
--------------------------------------------------------------------------------
/lib/helpers/projection/hasIncludedChildren.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * Creates an object that precomputes whether a given path has child fields in
5 | * the projection.
6 | *
7 | * #### Example:
8 | *
9 | * const res = hasIncludedChildren({ 'a.b.c': 0 });
10 | * res.a; // 1
11 | * res['a.b']; // 1
12 | * res['a.b.c']; // 1
13 | * res['a.c']; // undefined
14 | *
15 | * @param {Object} fields
16 | * @api private
17 | */
18 |
19 | module.exports = function hasIncludedChildren(fields) {
20 | const hasIncludedChildren = {};
21 | const keys = Object.keys(fields);
22 |
23 | for (const key of keys) {
24 |
25 | if (key.indexOf('.') === -1) {
26 | hasIncludedChildren[key] = 1;
27 | continue;
28 | }
29 | const parts = key.split('.');
30 | let c = parts[0];
31 |
32 | for (let i = 0; i < parts.length; ++i) {
33 | hasIncludedChildren[c] = 1;
34 | if (i + 1 < parts.length) {
35 | c = c + '.' + parts[i + 1];
36 | }
37 | }
38 | }
39 |
40 | return hasIncludedChildren;
41 | };
42 |
--------------------------------------------------------------------------------
/docs/css/copy-code.css:
--------------------------------------------------------------------------------
1 | /* Base button placement & visibility */
2 | .copy-btn {
3 | position: absolute;
4 | top: 6px;
5 | right: 6px;
6 | background: transparent;
7 | border: none;
8 | padding: 4px;
9 | cursor: pointer;
10 |
11 | opacity: 0;
12 | transform: translateY(-3px);
13 | transition: opacity 0.18s ease, transform 0.18s ease, color 0.2s ease;
14 |
15 | display: flex;
16 | align-items: center;
17 | justify-content: center;
18 |
19 | color: #666; /* default icon color */
20 | }
21 |
22 | /* Show button only when the code block is hovered */
23 | pre:hover .copy-btn {
24 | opacity: 1;
25 | transform: translateY(0);
26 | }
27 |
28 | /* Hover state always forces black — applies to both icons */
29 | .copy-btn:hover {
30 | color: #000 !important;
31 | }
32 |
33 | /* Tick icon uses the same neutral grey so hover can override cleanly */
34 | .copy-btn.copied {
35 | color: #666;
36 | }
37 |
38 | /* Icon sizing + smooth color transition */
39 | .copy-btn svg {
40 | width: 20px;
41 | height: 20px;
42 | transition: color 0.2s ease;
43 | }
44 |
--------------------------------------------------------------------------------
/lib/error/eachAsyncMultiError.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Module dependencies.
3 | */
4 |
5 | 'use strict';
6 |
7 | const MongooseError = require('./mongooseError');
8 |
9 |
10 | /**
11 | * If `eachAsync()` is called with `continueOnError: true`, there can be
12 | * multiple errors. This error class contains an `errors` property, which
13 | * contains an array of all errors that occurred in `eachAsync()`.
14 | *
15 | * @api private
16 | */
17 |
18 | class EachAsyncMultiError extends MongooseError {
19 | /**
20 | * @param {String} connectionString
21 | */
22 | constructor(errors) {
23 | let preview = errors.map(e => e.message).join(', ');
24 | if (preview.length > 50) {
25 | preview = preview.slice(0, 50) + '...';
26 | }
27 | super(`eachAsync() finished with ${errors.length} errors: ${preview}`);
28 |
29 | this.errors = errors;
30 | }
31 | }
32 |
33 | Object.defineProperty(EachAsyncMultiError.prototype, 'name', {
34 | value: 'EachAsyncMultiError'
35 | });
36 |
37 | /*!
38 | * exports
39 | */
40 |
41 | module.exports = EachAsyncMultiError;
42 |
--------------------------------------------------------------------------------
/test/helpers/isAsyncFunction.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const assert = require('assert');
4 | const isAsyncFunction = require('../../lib/helpers/isAsyncFunction');
5 |
6 | describe('isAsyncFunction', function() {
7 | it('should return false for non-functions', () => {
8 | assert.ok(!isAsyncFunction('a'));
9 | assert.ok(!isAsyncFunction(1));
10 | assert.ok(!isAsyncFunction(1n));
11 | assert.ok(!isAsyncFunction({}));
12 | assert.ok(!isAsyncFunction(new Date()));
13 | assert.ok(!isAsyncFunction([]));
14 | assert.ok(!isAsyncFunction(true));
15 | });
16 | it('should return false for sync function', () => {
17 | assert.ok(!isAsyncFunction(function syncFunction() { return 'a';}));
18 | });
19 | it('should return true for async function', () => {
20 | assert.ok(isAsyncFunction(async function asyncFunction() { return 'a';}));
21 | });
22 | it('should return false for sync function returning a Promise', () => {
23 | assert.ok(!isAsyncFunction(function promiseReturningFunction() { return Promise.resolve('a');}));
24 | });
25 | });
26 |
--------------------------------------------------------------------------------
/lib/helpers/discriminator/getConstructor.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const getDiscriminatorByValue = require('./getDiscriminatorByValue');
4 |
5 | /**
6 | * Find the correct constructor, taking into account discriminators
7 | * @api private
8 | */
9 |
10 | module.exports = function getConstructor(Constructor, value, defaultDiscriminatorValue) {
11 | const discriminatorKey = Constructor.schema.options.discriminatorKey;
12 | let discriminatorValue = (value != null && value[discriminatorKey]);
13 | if (discriminatorValue == null) {
14 | discriminatorValue = defaultDiscriminatorValue;
15 | }
16 | if (Constructor.discriminators &&
17 | discriminatorValue != null) {
18 | if (Constructor.discriminators[discriminatorValue]) {
19 | Constructor = Constructor.discriminators[discriminatorValue];
20 | } else {
21 | const constructorByValue = getDiscriminatorByValue(Constructor.discriminators, discriminatorValue);
22 | if (constructorByValue) {
23 | Constructor = constructorByValue;
24 | }
25 | }
26 | }
27 |
28 | return Constructor;
29 | };
30 |
--------------------------------------------------------------------------------
/test/schema.number.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const assert = require('assert');
4 | const start = require('./common');
5 |
6 | const mongoose = start.mongoose;
7 | const Schema = mongoose.Schema;
8 |
9 | describe('SchemaNumber', function() {
10 | it('allows 0 with required: true and ref set (gh-11912)', async function() {
11 | const schema = new Schema({ x: { type: Number, required: true, ref: 'Foo' } });
12 |
13 | await schema.path('x').doValidate(0);
14 | });
15 |
16 | it('allows calling `min()` with no message arg (gh-15236)', async function() {
17 | const schema = new Schema({ x: { type: Number } });
18 | schema.path('x').min(0);
19 |
20 | const err = await schema.path('x').doValidate(-1).then(() => null, err => err);
21 | assert.ok(err);
22 | assert.equal(err.message, 'Path `x` (-1) is less than minimum allowed value (0).');
23 |
24 | schema.path('x').min(0, 'Invalid value!');
25 |
26 | const err2 = await schema.path('x').doValidate(-1).then(() => null, err => err);
27 | assert.equal(err2.message, 'Invalid value!');
28 | });
29 | });
30 |
--------------------------------------------------------------------------------
/test/schema.boolean.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * Module dependencies.
5 | */
6 |
7 | const start = require('./common');
8 |
9 | const assert = require('assert');
10 |
11 | const mongoose = start.mongoose;
12 | const Schema = mongoose.Schema;
13 |
14 | describe('schematype', function() {
15 | describe('boolean', function() {
16 | it('null default is permitted (gh-523)', function(done) {
17 | mongoose.deleteModel(/Test/);
18 | const s1 = new Schema({ b: { type: Boolean, default: null } });
19 | const M1 = mongoose.model('Test1', s1);
20 | const s2 = new Schema({ b: { type: Boolean, default: false } });
21 | const M2 = mongoose.model('Test2', s2);
22 | const s3 = new Schema({ b: { type: Boolean, default: true } });
23 | const M3 = mongoose.model('Test3', s3);
24 |
25 | const m1 = new M1();
26 | assert.strictEqual(null, m1.b);
27 | const m2 = new M2();
28 | assert.strictEqual(false, m2.b);
29 | const m3 = new M3();
30 | assert.strictEqual(true, m3.b);
31 | done();
32 | });
33 | });
34 | });
35 |
--------------------------------------------------------------------------------
/benchmarks/insertManySimple.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const mongoose = require('../');
4 |
5 | run().catch(err => {
6 | console.error(err);
7 | process.exit(-1);
8 | });
9 |
10 | async function run() {
11 | await mongoose.connect('mongodb://127.0.0.1:27017/mongoose_benchmark');
12 | const FooSchema = new mongoose.Schema({ foo: String });
13 | const FooModel = mongoose.model('Foo', FooSchema);
14 |
15 | if (!process.env.MONGOOSE_BENCHMARK_SKIP_SETUP) {
16 | await FooModel.deleteMany({});
17 | }
18 |
19 | const numDocs = 1500;
20 | const docs = [];
21 | for (let i = 0; i < numDocs; ++i) {
22 | docs.push({ foo: 'test foo ' + i });
23 | }
24 |
25 | const numIterations = 200;
26 | const insertStart = Date.now();
27 | for (let i = 0; i < numIterations; ++i) {
28 | await FooModel.insertMany(docs);
29 | }
30 | const insertEnd = Date.now();
31 |
32 | const results = {
33 | 'Average insertMany time ms': +((insertEnd - insertStart) / numIterations).toFixed(2)
34 | };
35 |
36 | console.log(JSON.stringify(results, null, ' '));
37 | process.exit(0);
38 | }
39 |
--------------------------------------------------------------------------------
/benchmarks/createDeepNestedDocArray.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const mongoose = require('../');
4 |
5 | run().catch(err => {
6 | console.error(err);
7 | process.exit(-1);
8 | });
9 |
10 | async function run() {
11 | await mongoose.connect('mongodb://127.0.0.1:27017/mongoose_benchmark');
12 |
13 | const levels = 12;
14 |
15 | let schema = new mongoose.Schema({ test: { type: String, required: true } });
16 | let doc = { test: 'gh-14897' };
17 | for (let i = 0; i < levels; ++i) {
18 | schema = new mongoose.Schema({ level: Number, subdocs: [schema] });
19 | doc = { level: (levels - i), subdocs: [{ ...doc }, { ...doc }] };
20 | }
21 | const Test = mongoose.model('Test', schema);
22 |
23 | if (!process.env.MONGOOSE_BENCHMARK_SKIP_SETUP) {
24 | await Test.deleteMany({});
25 | }
26 |
27 | const insertStart = Date.now();
28 | await Test.create(doc);
29 | const insertEnd = Date.now();
30 |
31 | const results = {
32 | 'create() time ms': +(insertEnd - insertStart).toFixed(2)
33 | };
34 |
35 | console.log(JSON.stringify(results, null, ' '));
36 | process.exit(0);
37 | }
--------------------------------------------------------------------------------
/lib/cast/number.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const assert = require('assert');
4 |
5 | /**
6 | * Given a value, cast it to a number, or throw an `Error` if the value
7 | * cannot be casted. `null` and `undefined` are considered valid.
8 | *
9 | * @param {Any} value
10 | * @return {Number}
11 | * @throws {Error} if `value` is not one of the allowed values
12 | * @api private
13 | */
14 |
15 | module.exports = function castNumber(val) {
16 | if (val == null) {
17 | return val;
18 | }
19 | if (val === '') {
20 | return null;
21 | }
22 |
23 | if (typeof val === 'string' || typeof val === 'boolean') {
24 | val = Number(val);
25 | }
26 |
27 | assert.ok(!isNaN(val));
28 | if (val instanceof Number) {
29 | return val.valueOf();
30 | }
31 | if (typeof val === 'number') {
32 | return val;
33 | }
34 | if (!Array.isArray(val) && typeof val.valueOf === 'function') {
35 | return Number(val.valueOf());
36 | }
37 | if (val.toString && !Array.isArray(val) && val.toString() == Number(val)) {
38 | return Number(val);
39 | }
40 |
41 | assert.ok(false);
42 | };
43 |
--------------------------------------------------------------------------------
/lib/cast/uuid.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const UUID = require('mongodb/lib/bson').UUID;
4 |
5 | const UUID_FORMAT = /[0-9a-f]{8}-[0-9a-f]{4}-[0-9][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}/i;
6 |
7 | module.exports = function castUUID(value) {
8 | if (value == null) {
9 | return value;
10 | }
11 |
12 | if (value instanceof UUID) {
13 | return value;
14 | }
15 | if (typeof value === 'string') {
16 | if (UUID_FORMAT.test(value)) {
17 | return new UUID(value);
18 | } else {
19 | throw new Error(`"${value}" is not a valid UUID string`);
20 | }
21 | }
22 |
23 | // Re: gh-647 and gh-3030, we're ok with casting using `toString()`
24 | // **unless** its the default Object.toString, because "[object Object]"
25 | // doesn't really qualify as useful data
26 | if (value.toString && value.toString !== Object.prototype.toString) {
27 | if (UUID_FORMAT.test(value.toString())) {
28 | return new UUID(value.toString());
29 | }
30 | }
31 |
32 | throw new Error(`"${value}" cannot be casted to a UUID`);
33 | };
34 |
35 | module.exports.UUID_FORMAT = UUID_FORMAT;
36 |
--------------------------------------------------------------------------------
/lib/helpers/indexes/isIndexSpecEqual.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * Compares two index specifications to determine if they are equal.
5 | *
6 | * #### Example:
7 | * isIndexSpecEqual({ a: 1, b: 1 }, { a: 1, b: 1 }); // true
8 | * isIndexSpecEqual({ a: 1, b: 1 }, { b: 1, a: 1 }); // false
9 | * isIndexSpecEqual({ a: 1, b: -1 }, { a: 1, b: 1 }); // false
10 | *
11 | * @param {Object} spec1 The first index specification to compare.
12 | * @param {Object} spec2 The second index specification to compare.
13 | * @returns {Boolean} Returns true if the index specifications are equal, otherwise returns false.
14 | */
15 |
16 | module.exports = function isIndexSpecEqual(spec1, spec2) {
17 | const spec1Keys = Object.keys(spec1);
18 | const spec2Keys = Object.keys(spec2);
19 |
20 | if (spec1Keys.length !== spec2Keys.length) {
21 | return false;
22 | }
23 |
24 | for (let i = 0; i < spec1Keys.length; i++) {
25 | const key = spec1Keys[i];
26 | if (key !== spec2Keys[i] || spec1[key] !== spec2[key]) {
27 | return false;
28 | }
29 | }
30 |
31 | return true;
32 | };
33 |
--------------------------------------------------------------------------------
/test/parallelLimit.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const assert = require('assert');
4 | const parallelLimit = require('../lib/helpers/parallelLimit');
5 |
6 | describe('parallelLimit', function() {
7 | it('works with zero functions', async function() {
8 | const results = await parallelLimit([], value => Promise.resolve(value), 1);
9 | assert.deepEqual(results, []);
10 | });
11 |
12 | it('executes functions in parallel', async function() {
13 | let started = 0;
14 | let finished = 0;
15 | const params = [1, 2, 3];
16 |
17 | const fn = async() => {
18 | ++started;
19 | await new Promise(resolve => setTimeout(resolve, 10));
20 | ++finished;
21 | return finished;
22 | };
23 |
24 | const results = await parallelLimit(params, async(param, index) => {
25 | if (index === 2) {
26 | assert.equal(started, 2);
27 | assert.ok(finished > 0);
28 | }
29 | return fn();
30 | }, 2);
31 |
32 | assert.equal(started, 3);
33 | assert.equal(finished, 3);
34 | assert.deepStrictEqual(results, [1, 2, 3]);
35 | });
36 | });
37 |
--------------------------------------------------------------------------------
/test/types/queryhelpers.test.ts:
--------------------------------------------------------------------------------
1 | import { HydratedDocument, Model, Query, Schema, model } from 'mongoose';
2 |
3 | interface Project {
4 | name: string;
5 | stars: number;
6 | }
7 |
8 | type ProjectModelType = Model;
9 | // Query helpers should return `Query> & ProjectQueryHelpers`
10 | // to enable chaining.
11 | type ProjectModelQuery = Query, ProjectQueryHelpers, any> & ProjectQueryHelpers;
12 | interface ProjectQueryHelpers {
13 | byName(this: ProjectModelQuery, name: string): ProjectModelQuery;
14 | }
15 |
16 | const schema = new Schema({
17 | name: { type: String, required: true },
18 | stars: { type: Number, required: true }
19 | });
20 | schema.query.byName = function(name: string): ProjectModelQuery {
21 | return this.find({ name: name });
22 | };
23 |
24 | // 2nd param to `model()` is the Model class to return.
25 | const ProjectModel = model('Project', schema);
26 |
27 | ProjectModel.find().where('stars').gt(1000).byName('mongoose').exec();
28 |
--------------------------------------------------------------------------------
/lib/helpers/projection/isInclusive.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const isDefiningProjection = require('./isDefiningProjection');
4 | const isPOJO = require('../isPOJO');
5 |
6 | /*!
7 | * ignore
8 | */
9 |
10 | module.exports = function isInclusive(projection) {
11 | if (projection == null) {
12 | return false;
13 | }
14 |
15 | const props = Object.keys(projection);
16 | const numProps = props.length;
17 | if (numProps === 0) {
18 | return false;
19 | }
20 |
21 | for (let i = 0; i < numProps; ++i) {
22 | const prop = props[i];
23 | // Plus paths can't define the projection (see gh-7050)
24 | if (prop.startsWith('+')) {
25 | continue;
26 | }
27 | // If field is truthy (1, true, etc.) and not an object, then this
28 | // projection must be inclusive. If object, assume its $meta, $slice, etc.
29 | if (isDefiningProjection(projection[prop]) && !!projection[prop]) {
30 | if (isPOJO(projection[prop])) {
31 | return isInclusive(projection[prop]);
32 | } else {
33 | return !!projection[prop];
34 | }
35 | }
36 | }
37 |
38 | return false;
39 | };
40 |
--------------------------------------------------------------------------------
/tools/sharded.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | run().catch(error => {
4 | console.error(error);
5 | process.exit(-1);
6 | });
7 |
8 |
9 | async function run() {
10 | const Sharded = require('mongodb-topology-manager').Sharded;
11 |
12 | // Create new instance
13 | const topology = new Sharded({
14 | mongod: 'mongod',
15 | mongos: 'mongos'
16 | });
17 |
18 | await topology.addShard([{
19 | options: {
20 | bind_ip: '127.0.0.1', port: 31000, dbpath: '/data/db/31000', shardsvr: null
21 | }
22 | }], { replSet: 'rs1' });
23 |
24 | await topology.addConfigurationServers([{
25 | options: {
26 | bind_ip: '127.0.0.1', port: 35000, dbpath: '/data/db/35000'
27 | }
28 | }], { replSet: 'rs0' });
29 |
30 | await topology.addProxies([{
31 | bind_ip: '127.0.0.1', port: 51000, configdb: '127.0.0.1:35000'
32 | }], {
33 | binary: 'mongos'
34 | });
35 |
36 | console.log('Start...');
37 | // Start up topology
38 | await topology.start();
39 |
40 | console.log('Started');
41 |
42 | // Shard db
43 | await topology.enableSharding('test');
44 |
45 | console.log('done');
46 | }
47 |
--------------------------------------------------------------------------------
/docs/images/search.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/lib/helpers/schema/merge.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | module.exports = function merge(s1, s2, skipConflictingPaths) {
4 | const paths = Object.keys(s2.tree);
5 | const pathsToAdd = {};
6 | for (const key of paths) {
7 | if (skipConflictingPaths && (s1.paths[key] || s1.nested[key] || s1.singleNestedPaths[key])) {
8 | continue;
9 | }
10 | pathsToAdd[key] = s2.tree[key];
11 | }
12 | s1.options._isMerging = true;
13 | s1.add(pathsToAdd, null);
14 | delete s1.options._isMerging;
15 |
16 | s1.callQueue = s1.callQueue.concat(s2.callQueue);
17 | s1.method(s2.methods);
18 | s1.static(s2.statics);
19 |
20 | for (const [option, value] of Object.entries(s2._userProvidedOptions)) {
21 | if (!(option in s1._userProvidedOptions)) {
22 | s1.set(option, value);
23 | }
24 | }
25 |
26 | for (const query in s2.query) {
27 | s1.query[query] = s2.query[query];
28 | }
29 |
30 | for (const virtual in s2.virtuals) {
31 | s1.virtuals[virtual] = s2.virtuals[virtual].clone();
32 | }
33 |
34 | s1._indexes = s1._indexes.concat(s2._indexes || []);
35 | s1.s.hooks.merge(s2.s.hooks, false);
36 | };
37 |
--------------------------------------------------------------------------------
/docs/css/inlinecpc.css:
--------------------------------------------------------------------------------
1 | .native-inline {
2 | visibility: hidden;
3 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu,
4 | Cantarell, "Helvetica Neue", Helvetica, Arial, sans-serif;
5 | opacity: 0;
6 | transition: all .25s ease-in-out;
7 | }
8 |
9 | .native-show {
10 | visibility: visible;
11 | opacity: 1;
12 | }
13 |
14 | .native-inline {
15 | display: block;
16 | margin-top: 1.5em;
17 | padding: 10px 20px;
18 | border-radius: 4px;
19 | background: repeating-linear-gradient(-45deg, transparent, transparent 5px, hsla(0, 0%, 0%, .03) 5px, hsla(0, 0%, 0%, .03) 10px) hsla(0, 0%, 0%, .03);
20 | }
21 |
22 | .native-inline a {
23 | display: block;
24 | text-decoration: none;
25 | line-height: 1.5;
26 | }
27 |
28 |
29 | .native-inline .sponsor {
30 | position: relative;
31 | top: -1px;
32 | margin-right: 4px;
33 | padding: 2px 6px 3px;
34 | border: solid 1px currentColor;
35 | border-radius: 2px;
36 | color: currentColor;
37 | content: "Sponsor";
38 | text-transform: uppercase;
39 | letter-spacing: 1px;
40 | font-weight: 600;
41 | font-size: 11px;
42 | line-height: 1;
43 | }
44 |
--------------------------------------------------------------------------------
/lib/cast/decimal128.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const Decimal128Type = require('../types/decimal128');
4 | const assert = require('assert');
5 |
6 | module.exports = function castDecimal128(value) {
7 | if (value == null) {
8 | return value;
9 | }
10 |
11 | if (typeof value === 'object' && typeof value.$numberDecimal === 'string') {
12 | return Decimal128Type.fromString(value.$numberDecimal);
13 | }
14 |
15 | if (value instanceof Decimal128Type) {
16 | return value;
17 | }
18 |
19 | if (typeof value === 'string') {
20 | return Decimal128Type.fromString(value);
21 | }
22 |
23 | if (typeof Buffer === 'function' && Buffer.isBuffer(value)) {
24 | return new Decimal128Type(value);
25 | }
26 | if (typeof Uint8Array === 'function' && value instanceof Uint8Array) {
27 | return new Decimal128Type(value);
28 | }
29 |
30 | if (typeof value === 'number') {
31 | return Decimal128Type.fromString(String(value));
32 | }
33 |
34 | if (typeof value.valueOf === 'function' && typeof value.valueOf() === 'string') {
35 | return Decimal128Type.fromString(value.valueOf());
36 | }
37 |
38 | assert.ok(false);
39 | };
40 |
--------------------------------------------------------------------------------
/lib/cast/string.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const CastError = require('../error/cast');
4 |
5 | /**
6 | * Given a value, cast it to a string, or throw a `CastError` if the value
7 | * cannot be casted. `null` and `undefined` are considered valid.
8 | *
9 | * @param {Any} value
10 | * @param {String} [path] optional the path to set on the CastError
11 | * @return {string|null|undefined}
12 | * @throws {CastError}
13 | * @api private
14 | */
15 |
16 | module.exports = function castString(value, path) {
17 | // If null or undefined
18 | if (value == null) {
19 | return value;
20 | }
21 |
22 | // handle documents being passed
23 | if (value._id && typeof value._id === 'string') {
24 | return value._id;
25 | }
26 |
27 | // Re: gh-647 and gh-3030, we're ok with casting using `toString()`
28 | // **unless** its the default Object.toString, because "[object Object]"
29 | // doesn't really qualify as useful data
30 | if (value.toString &&
31 | value.toString !== Object.prototype.toString &&
32 | !Array.isArray(value)) {
33 | return value.toString();
34 | }
35 |
36 | throw new CastError('string', value, path);
37 | };
38 |
--------------------------------------------------------------------------------
/lib/error/bulkWriteError.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Module dependencies.
3 | */
4 |
5 | 'use strict';
6 |
7 | const MongooseError = require('./');
8 |
9 |
10 | /**
11 | * If `bulkWrite()` or `insertMany()` has validation errors, but
12 | * all valid operations succeed, and 'throwOnValidationError' is true,
13 | * Mongoose will throw this error.
14 | *
15 | * @api private
16 | */
17 |
18 | class MongooseBulkWriteError extends MongooseError {
19 | constructor(validationErrors, results, rawResult, operation) {
20 | let preview = validationErrors.map(e => e.message).join(', ');
21 | if (preview.length > 200) {
22 | preview = preview.slice(0, 200) + '...';
23 | }
24 | super(`${operation} failed with ${validationErrors.length} Mongoose validation errors: ${preview}`);
25 |
26 | this.validationErrors = validationErrors;
27 | this.results = results;
28 | this.rawResult = rawResult;
29 | this.operation = operation;
30 | }
31 | }
32 |
33 | Object.defineProperty(MongooseBulkWriteError.prototype, 'name', {
34 | value: 'MongooseBulkWriteError'
35 | });
36 |
37 | /*!
38 | * exports
39 | */
40 |
41 | module.exports = MongooseBulkWriteError;
42 |
--------------------------------------------------------------------------------
/lib/helpers/schema/getSubdocumentStrictValue.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * Find the `strict` mode setting for the deepest subdocument along a given path
5 | * to ensure we have the correct default value for `strict`. When setting values
6 | * underneath a subdocument, we should use the subdocument's `strict` setting by
7 | * default, not the top-level document's.
8 | *
9 | * @param {Schema} schema
10 | * @param {String[]} parts
11 | * @returns {boolean | 'throw' | undefined}
12 | */
13 |
14 | module.exports = function getSubdocumentStrictValue(schema, parts) {
15 | if (parts.length === 1) {
16 | return undefined;
17 | }
18 | let cur = parts[0];
19 | let strict = undefined;
20 | for (let i = 0; i < parts.length - 1; ++i) {
21 | const curSchemaType = schema.path(cur);
22 | if (curSchemaType && curSchemaType.schema) {
23 | strict = curSchemaType.schema.options.strict;
24 | schema = curSchemaType.schema;
25 | cur = curSchemaType.$isMongooseDocumentArray && !isNaN(parts[i + 1]) ? '' : parts[i + 1];
26 | } else {
27 | cur += cur.length ? ('.' + parts[i + 1]) : parts[i + 1];
28 | }
29 | }
30 |
31 | return strict;
32 | };
33 |
--------------------------------------------------------------------------------
/release-items.md:
--------------------------------------------------------------------------------
1 | # Release procedure
2 |
3 | ## mongoose release procedure
4 |
5 | 1. tests must pass
6 | 2. update `package.json` and `package-lock.json` version
7 | 3. update `CHANGELOG.md`. Add # as well as a link to the github user who fixed it if applicable.
8 | 4. git commit -a -m 'release x.x.x'
9 | 5. git tag x.x.x
10 | 6. `npm run release`, or `npm run release-legacy` for 4.x
11 | 7. update mongoosejs.com (see "updating the website" below)
12 | 8. tweet changelog link from [@mongoosejs](https://twitter.com/mongoosejs)
13 | 9. Announce on mongoosejsteam slack channel
14 | 10. if this is a legacy release, `git merge` changes into master.
15 |
16 | ## updating the website
17 |
18 | For 6.x
19 |
20 | 0. Change to the master branch
21 | 1. execute `npm run docs:prepare:publish:stable` (when this process completes you'll be on the gh-pages branch)
22 | 2. `git commit -a -m 'chore: website 6.x.x'`
23 | 3. `git push origin gh-pages`
24 |
25 | For 5.x
26 |
27 | 0. Change to the 5.x branch
28 | 1. execute `make docs_legacy` (when this process completes you'll be on the gh-pages branch)
29 | 2. `git commit -a -m 'chore: website 5.x.x'`
30 | 3. `git push origin gh-pages`
31 |
--------------------------------------------------------------------------------
/test/helpers/query.selectPopulatedFields.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const assert = require('assert');
4 | const selectPopulatedFields = require('../../lib/helpers/query/selectPopulatedFields');
5 |
6 | describe('selectPopulatedFields', function() {
7 | it('selects refPath', function() {
8 | const fields = { name: 1 };
9 | const userProvidedFields = { name: 1 };
10 | const populateOptions = {
11 | parent: {
12 | refPath: 'parentModel'
13 | }
14 | };
15 | selectPopulatedFields(fields, userProvidedFields, populateOptions);
16 | assert.deepStrictEqual(fields, {
17 | name: 1,
18 | parent: 1,
19 | parentModel: 1
20 | });
21 | });
22 |
23 | it('adds refPath to projection if not deselected by user in exclusive projection', function() {
24 | const fields = { name: 0, parentModel: 0 };
25 | const userProvidedFields = { name: 0 };
26 | const populateOptions = {
27 | parent: {
28 | refPath: 'parentModel'
29 | }
30 | };
31 | selectPopulatedFields(fields, userProvidedFields, populateOptions);
32 | assert.deepStrictEqual(fields, {
33 | name: 0
34 | });
35 | });
36 | });
37 |
--------------------------------------------------------------------------------
/lib/helpers/model/applyStaticHooks.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | const { queryMiddlewareFunctions, aggregateMiddlewareFunctions, modelMiddlewareFunctions, documentMiddlewareFunctions } = require('../../constants');
4 |
5 | const middlewareFunctions = Array.from(
6 | new Set([
7 | ...queryMiddlewareFunctions,
8 | ...aggregateMiddlewareFunctions,
9 | ...modelMiddlewareFunctions,
10 | ...documentMiddlewareFunctions
11 | ])
12 | );
13 |
14 | module.exports = function applyStaticHooks(model, hooks, statics) {
15 | hooks = hooks.filter(hook => {
16 | // If the custom static overwrites an existing middleware, don't apply
17 | // middleware to it by default. This avoids a potential backwards breaking
18 | // change with plugins like `mongoose-delete` that use statics to overwrite
19 | // built-in Mongoose functions.
20 | if (middlewareFunctions.indexOf(hook.name) !== -1) {
21 | return !!hook.model;
22 | }
23 | return hook.model !== false;
24 | });
25 |
26 | for (const key of Object.keys(statics)) {
27 | if (hooks.hasHooks(key)) {
28 | const original = model[key];
29 |
30 | model[key] = hooks.createWrapper(key, original);
31 | }
32 | }
33 | };
34 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | # MIT License
2 |
3 | Copyright (c) 2010-2013 LearnBoost
4 | Copyright (c) 2013-2021 Automattic
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy
7 | of this software and associated documentation files (the "Software"), to deal
8 | in the Software without restriction, including without limitation the rights
9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 | copies of the Software, and to permit persons to whom the Software is
11 | furnished to do so, subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 | SOFTWARE.
23 |
--------------------------------------------------------------------------------
/lib/helpers/populate/setPopulatedVirtualValue.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | /**
4 | * Set a populated virtual value on a document's `$$populatedVirtuals` value
5 | *
6 | * @param {*} populatedVirtuals A document's `$$populatedVirtuals`
7 | * @param {*} name The virtual name
8 | * @param {*} v The result of the populate query
9 | * @param {*} options The populate options. This function handles `justOne` and `count` options.
10 | * @returns {Array|Document|Object|Array