-
-
Notifications
You must be signed in to change notification settings - Fork 4k
Description
Prerequisites
- I have written a descriptive issue title
- I have searched existing issues to ensure the bug has not already been reported
Mongoose version
9.2.4
Node.js version
25.8.0
MongoDB server version
not applicable (no connection necessary)
Typescript version (if applicable)
No response
Description
(Disclaimer: I stumbled upon this bug myself. The following description is mostly generated by AI, but I debugged the logic flow myself and concluded, that the reasoning is correct.)
The JSDoc for Model.hydrate() declares the projection parameter as {object|string|string[]}, but passing a string (e.g. 'name') causes unexpected behavior — all fields get stripped from the hydrated document.
What happens
When projection is a string like 'name', applyProjection() calls Object.keys('name') which returns character indices ['0', '1', '2', '3']. Then isInclusive() sees projection['0'] = 'n' (truthy), treats it as an inclusive projection, and applyInclusiveProjection() tries to keep only fields named '0', '1', '2', '3' — effectively deleting all real document fields.
Relevant code
Model.hydrate()passes the rawprojectiontoapplyProjection()andcreateModel()without any type coercion.applyProjection()and its helpers (isInclusive,isExclusive) callObject.keys()on the projection, which on a string returns character indices instead of field names.
Steps to Reproduce
const mongoose = require('.'); // require('mongoose')
const schema = new mongoose.Schema({ name: String, type: String });
const Candy = mongoose.model('Candy', schema);
const doc = Candy.hydrate(
{ _id: '54108337212ffb6d459f854c', name: 'jelly bean', type: 'sweet' },
'name'
);
console.log(doc.toObject()); // Expected: { name: 'jelly bean' }
// Actual: {}Expected Behavior
Either:
- Convert string/array projections to a projection object (like
Querydoes), so'name'becomes{ name: 1 }and['name', 'type']becomes{ name: 1, type: 1 }, or - Validate the
projectionparameter type and throw a descriptive error if it's not a plain object, or - Update the JSDoc to only advertise
objectas the accepted type.
If the 1st option is chosen, then the code:
const doc = Candy.hydrate(
{ _id: '54108337212ffb6d459f854c', name: 'jelly bean', type: 'sweet' },
'name'
);
console.log(doc.toObject());should behave like:
const doc = Candy.hydrate(
{ _id: '54108337212ffb6d459f854c', name: 'jelly bean', type: 'sweet' },
{ name: 1 }
);
console.log(doc.toObject());