Skip to content

fix(DocumentArray): correctly set parent if instantiated with schema from another Mongoose instance #15471

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ jobs:
key: ${{ matrix.os }}-${{ matrix.mongodb }}

- run: npm install
# Create ./node_modules/mongoose-separate-require-instance for testing multiple require instances
- run: npm run create-separate-require-instance
- name: NPM Test without Coverage
run: npm test
if: matrix.coverage != true
Expand Down
3 changes: 3 additions & 0 deletions lib/document.js
Original file line number Diff line number Diff line change
Expand Up @@ -2756,6 +2756,9 @@ function _getPathsToValidate(doc, pathsToValidate, pathsToSkip, isNestedValidate
}

const subdocParent = subdoc.$parent();
if (subdocParent == null) {
throw new Error('Cannot validate subdocument that does not have a parent');
}
if (doc.$isModified(fullPathToSubdoc, null, modifiedPaths) &&
// Avoid using isDirectModified() here because that does additional checks on whether the parent path
// is direct modified, which can cause performance issues re: gh-14897
Expand Down
7 changes: 1 addition & 6 deletions lib/types/array/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

'use strict';

const Document = require('../../document');
const mongooseArrayMethods = require('./methods');

const arrayAtomicsSymbol = require('../../helpers/symbols').arrayAtomicsSymbol;
Expand Down Expand Up @@ -73,11 +72,7 @@ function MongooseArray(values, path, doc, schematype) {
internals[arrayAtomicsSymbol] = values[arrayAtomicsSymbol];
}

// Because doc comes from the context of another function, doc === global
// can happen if there was a null somewhere up the chain (see #3020)
// RB Jun 17, 2015 updated to check for presence of expected paths instead
// to make more proof against unusual node environments
if (doc != null && doc instanceof Document) {
if (doc != null && doc.$__) {
internals[arrayParentSymbol] = doc;
internals[arraySchemaSymbol] = schematype || doc.schema.path(path);
}
Expand Down
7 changes: 1 addition & 6 deletions lib/types/documentArray/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@

const ArrayMethods = require('../array/methods');
const DocumentArrayMethods = require('./methods');
const Document = require('../../document');

const arrayAtomicsSymbol = require('../../helpers/symbols').arrayAtomicsSymbol;
const arrayAtomicsBackupSymbol = require('../../helpers/symbols').arrayAtomicsBackupSymbol;
Expand Down Expand Up @@ -51,11 +50,7 @@ function MongooseDocumentArray(values, path, doc, schematype) {
internals[arrayPathSymbol] = path;
internals.__array = __array;

// Because doc comes from the context of another function, doc === global
// can happen if there was a null somewhere up the chain (see #3020 && #3034)
// RB Jun 17, 2015 updated to check for presence of expected paths instead
// to make more proof against unusual node environments
if (doc && doc instanceof Document) {
if (doc && doc.$__) {
internals[arrayParentSymbol] = doc;
internals[arraySchemaSymbol] = doc.$__schema.path(path);

Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@
"release-6x": "git pull origin 6.x && git push origin 6.x && git push origin 6.x --tags && npm publish --tag 6x",
"mongo": "node ./tools/repl.js",
"publish-7x": "npm publish --tag 7x",
"create-separate-require-instance": "rm -rf ./node_modules/mongoose-separate-require-instance && node ./scripts/create-tarball && tar -xzf mongoose.tgz -C ./node_modules && mv ./node_modules/package ./node_modules/mongoose-separate-require-instance",
"test": "mocha --exit ./test/*.test.js",
"test-deno": "deno run --allow-env --allow-read --allow-net --allow-run --allow-sys --allow-write ./test/deno.mjs",
"test-rs": "START_REPLICA_SET=1 mocha --timeout 30000 --exit ./test/*.test.js",
Expand Down
46 changes: 46 additions & 0 deletions test/multiple-require-instance.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
'use strict';

const start = require('./common');

let mongoose2;

describe('multiple require instance', function() {
before(function() {
try {
mongoose2 = require('mongoose-separate-require-instance');
} catch (err) {
return this.skip();
}
});

let db;
beforeEach(function() {
db = start();
});
afterEach(() => db.close());

it('supports arrays defined using schemas from separate instance (gh-15466)', async function() {
const nestedSchema = new mongoose2.Schema(
{ name: String },
{ _id: false }
);

const schema = new mongoose2.Schema({
subDoc: nestedSchema,
docArray: [nestedSchema] // this array of nestedSchema causes the error
});

const document = {
subDoc: { name: 'Alpha' },
docArray: [
{ name: 'Bravo' },
{ name: 'Charlie' }
]
};

const TestModel = db.model('Test', schema);
const doc = new TestModel(document);
await doc.validate();

});
});