Skip to content
Open
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
46 changes: 30 additions & 16 deletions lib/types/documentArray/methods/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@

const ArrayMethods = require('../../array/methods');
const Document = require('../../../document');
const castObjectId = require('../../../cast/objectid');
const getDiscriminatorByValue = require('../../../helpers/discriminator/getDiscriminatorByValue');
const internalToObjectOptions = require('../../../options').internalToObjectOptions;
const utils = require('../../../utils');
Expand Down Expand Up @@ -121,42 +120,57 @@ const methods = {
*
* @return {EmbeddedDocument|null} the subdocument or null if not found.
* @param {ObjectId|String|Number|Buffer} id
* @TODO cast to the _id based on schema for proper comparison
* @method id
* @api public
* @memberOf MongooseDocumentArray
*/

id(id) {
let casted;
let sid;
let _id;
if (id == null) {
return null;
}

try {
casted = castObjectId(id).toString();
} catch (e) {
casted = null;
const schemaType = this[arraySchemaSymbol];
let idSchemaType = null;

if (schemaType && schemaType.schema) {
idSchemaType = schemaType.schema.path('_id');
} else if (schemaType && schemaType.casterConstructor && schemaType.casterConstructor.schema) {
idSchemaType = schemaType.casterConstructor.schema.path('_id');
}

let castedId = null;
if (idSchemaType) {
try {
castedId = idSchemaType.cast(id);
} catch (e) {
castedId = null;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldnt it still be null already?

}
}

let _id;

for (const val of this) {
if (!val) {
continue;
}

_id = val.get('_id');

if (_id === null || typeof _id === 'undefined') {
if (_id == null) {
continue;
} else if (_id instanceof Document) {
sid || (sid = String(id));
if (sid == _id._id) {
_id = _id.get('_id');
if (castedId != null && utils.deepEqual(castedId, _id)) {
return val;
}
} else if (!isBsonType(id, 'ObjectId') && !isBsonType(_id, 'ObjectId')) {
if (id == _id || utils.deepEqual(id, _id)) {
} else if (castedId == null && (id == _id || utils.deepEqual(id, _id))) {
// Backwards compat: compare user-specified param to _id using loose equality
return val;
}
} else if (casted == _id) {
} else if (castedId != null && utils.deepEqual(castedId, _id)) {
return val;
} else if (castedId == null && (_id == id || utils.deepEqual(id, _id))) {
// Backwards compat: compare user-specified param to _id using loose equality
return val;
}
}
Expand Down
17 changes: 16 additions & 1 deletion test/types.documentarray.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ describe('types.documentarray', function() {
sub1.title = 'Hello again to all my friends';
let id = sub1.id;

let a = new MongooseDocumentArray([sub1]);
let a = new MongooseDocumentArray([sub1], 'test', null);
assert.equal(a.id(id).title, 'Hello again to all my friends');
assert.equal(a.id(sub1._id).title, 'Hello again to all my friends');

Expand Down Expand Up @@ -186,8 +186,23 @@ describe('types.documentarray', function() {

a = new MongooseDocumentArray([sub]);
assert.equal(a.id(id).title, 'Hello again to all my friends');
});

it('#id with custom schematype (gh-15725)', function() {
const schema = new Schema({ _id: Number, name: String });
const Subdocument = TestDoc(schema);

const sub1 = new Subdocument();
sub1._id = 42;
sub1.title = 'Hello again to all my friends';

const parentDoc = { $__: true, $__schema: new Schema({ subdocs: [schema] }) };

const a = new MongooseDocumentArray([sub1], 'test', parentDoc);
Copy link

Copilot AI Nov 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The path name mismatch between the schema definition and array constructor could cause the test to fail. The parent schema defines a field named subdocs (line 199), but the MongooseDocumentArray is instantiated with path 'test' (line 201). This mismatch means doc.$__schema.path('test') will return undefined, preventing the schema-based casting logic from working. The path should be 'subdocs' to match the schema definition.

Suggested change
const a = new MongooseDocumentArray([sub1], 'test', parentDoc);
const a = new MongooseDocumentArray([sub1], 'subdocs', parentDoc);

Copilot uses AI. Check for mistakes.
assert.equal(a.id('42').title, 'Hello again to all my friends');
assert.equal(a.id(sub1.id).title, 'Hello again to all my friends');
assert.ok(!a.id('43'));
assert.ok(!a.id('not a number'));
});

describe('inspect', function() {
Expand Down
Loading