Skip to content

Conversation

@Lex-Ashu
Copy link
Contributor

@Lex-Ashu Lex-Ashu commented Nov 6, 2025

Closes #15724

Summary

The DocumentArray.id() method was always attempting to cast the id parameter to ObjectId, which caused issues when using custom _id types like String, Number, or Object. This fix implements schema-based casting by:

  1. Getting the _id schema type from the document array schema
  2. Casting the input id parameter to match that type before comparison
  3. Maintaining backward compatibility with ObjectId fallback

This resolves the TODO comment at line 124 and ensures the method works correctly with all _id types that Mongoose supports.

Example demonstrating the fix:

// Schema with custom String _id
const CustomSchema = new Schema({
  _id: { type: String, required: true },
  name: String,
});

const ParentSchema = new Schema({ children: [CustomSchema] });
const Parent = mongoose.model("Parent", ParentSchema);

// Create a parent document with a child
const parent = new Parent({ children: [{ _id: "abc123", name: "test" }] });
await parent.save();

// Before this fix, parent.children.id('abc123') would fail to find the document
// because 'abc123' would be incorrectly cast to an ObjectId.
// After this fix, it correctly casts 'abc123' to a String and finds the document.
const found = parent.children.id("abc123");
console.log(found); // Will now correctly output the embedded document: { _id: 'abc123', name: 'test' }

Fixes Automattic#15724

The id() method now properly casts the id parameter based on the schema's
_id type instead of always attempting to cast to ObjectId. This fixes
issues when using custom _id types like String, Number, or Object.
@vkarpov15 vkarpov15 requested a review from Copilot November 7, 2025 15:43
Copy link
Collaborator

@vkarpov15 vkarpov15 left a comment

Choose a reason for hiding this comment

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

Good overall direction, just have a few suggestions

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR implements schema-based casting for the id() method in the DocumentArray type, addressing a TODO comment that was previously in the code. The implementation now attempts to cast the input id parameter using the schema's _id field type before performing comparisons.

Key changes:

  • Adds schema-aware casting of the input id parameter using the _id field's schema type
  • Refactors the comparison logic to use the casted id value for more accurate matching
  • Removes the TODO comment indicating this feature has been implemented

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@Lex-Ashu Lex-Ashu requested review from Copilot and vkarpov15 November 8, 2025 12:08
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 4 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +180 to 181
} else if (castedId == null && (id == _id || utils.deepEqual(id, _id))) {
return val;
Copy link

Copilot AI Nov 8, 2025

Choose a reason for hiding this comment

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

[nitpick] The fallback condition else if (castedId == null && (id == _id || utils.deepEqual(id, _id))) could potentially match when casting failed but the original id happens to match. This might give false positives if the intent is that casting failure should prevent matches.

Consider whether this fallback is necessary, or if a failed cast should always result in no match. If the fallback is intentional, a comment explaining why would be helpful.

Suggested change
} else if (castedId == null && (id == _id || utils.deepEqual(id, _id))) {
return val;

Copilot uses AI. Check for mistakes.
Comment on lines +170 to 182
} else if (castedId != null && !isBsonType(castedId, 'ObjectId') && !isBsonType(_id, 'ObjectId')) {
if (castedId == _id || utils.deepEqual(castedId, _id)) {
return val;
}
} else if (casted == _id) {
} else if (castedId != null && isBsonType(castedId, 'ObjectId') && isBsonType(_id, 'ObjectId')) {
if (castedId.toString() === _id.toString()) {
return val;
}
} else if (castedId != null && castedId == _id) {
return val;
} else if (castedId == null && (id == _id || utils.deepEqual(id, _id))) {
return val;
}
Copy link

Copilot AI Nov 8, 2025

Choose a reason for hiding this comment

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

[nitpick] The comparison logic starting at line 170 handles multiple scenarios but lacks explanatory comments. Consider adding brief comments for each condition to improve maintainability:

// Both castedId and _id are non-ObjectId types (e.g., string, number, object)
} else if (castedId != null && !isBsonType(castedId, 'ObjectId') && !isBsonType(_id, 'ObjectId')) {
  if (castedId == _id || utils.deepEqual(castedId, _id)) {
    return val;
  }
// Both castedId and _id are ObjectIds - compare as strings
} else if (castedId != null && isBsonType(castedId, 'ObjectId') && isBsonType(_id, 'ObjectId')) {
  if (castedId.toString() === _id.toString()) {
    return val;
  }
// Mixed types or other valid castedId scenarios
} else if (castedId != null && castedId == _id) {
  return val;
// Fallback to original id when casting failed
} else if (castedId == null && (id == _id || utils.deepEqual(id, _id))) {
  return val;
}

Copilot uses AI. Check for mistakes.
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Copy link
Collaborator

@vkarpov15 vkarpov15 left a comment

Choose a reason for hiding this comment

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

LGTM, I'll merge this into a separate branch so I can do some cleanup but otherwise I will merge this into 8.20.

@vkarpov15 vkarpov15 changed the base branch from master to vkarpov15/gh-15725 November 10, 2025 15:39
@vkarpov15 vkarpov15 merged commit ce7e016 into Automattic:vkarpov15/gh-15725 Nov 10, 2025
@vkarpov15 vkarpov15 added this to the 8.20 milestone Nov 10, 2025
vkarpov15 added a commit that referenced this pull request Nov 10, 2025
vkarpov15 added a commit that referenced this pull request Nov 13, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

DocumentArray.id() doesn't properly cast id parameter for custom _id types (String, Number, etc.)

2 participants