Skip to content

Commit

Permalink
feat(document): add flattenObjectIds option to toObject() and toJSON()
Browse files Browse the repository at this point in the history
Fix #13341
Re: #2790
  • Loading branch information
vkarpov15 committed May 6, 2023
1 parent 1c4e6a9 commit 5d93dff
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 0 deletions.
15 changes: 15 additions & 0 deletions lib/document.js
Original file line number Diff line number Diff line change
Expand Up @@ -3637,6 +3637,15 @@ Document.prototype.$toObject = function(options, json) {
flattenMaps = schemaOptions.flattenMaps;
}

let flattenObjectIds;
if (options._calledWithOptions.flattenObjectIds != null) {
flattenObjectIds = options.flattenObjectIds;
} else if (defaultOptions.flattenObjectIds != null) {
flattenObjectIds = defaultOptions.flattenObjectIds;
} else {
flattenObjectIds = schemaOptions.flattenObjectIds;
}

// The original options that will be passed to `clone()`. Important because
// `clone()` will recursively call `$toObject()` on embedded docs, so we
// need the original options the user passed in, plus `_isNested` and
Expand All @@ -3646,6 +3655,7 @@ Document.prototype.$toObject = function(options, json) {
json: json,
minimize: _minimize,
flattenMaps: flattenMaps,
flattenObjectIds: flattenObjectIds,
_seen: (options && options._seen) || new Map()
});

Expand Down Expand Up @@ -3861,6 +3871,7 @@ Document.prototype.$toObject = function(options, json) {
* @param {Boolean} [options.depopulate=false] if true, replace any conventionally populated paths with the original id in the output. Has no affect on virtual populated paths.
* @param {Boolean} [options.versionKey=true] if false, exclude the version key (`__v` by default) from the output
* @param {Boolean} [options.flattenMaps=false] if true, convert Maps to POJOs. Useful if you want to `JSON.stringify()` the result of `toObject()`.
* @param {Boolean} [options.flattenObjectIds=false] if true, convert any ObjectIds in the result to 24 character hex strings.
* @param {Boolean} [options.useProjection=false] - If true, omits fields that are excluded in this document's projection. Unless you specified a projection, this will omit any field that has `select: false` in the schema.
* @return {Object} js object (not a POJO)
* @see mongodb.Binary https://mongodb.github.io/node-mongodb-native/4.9/classes/Binary.html
Expand Down Expand Up @@ -4142,6 +4153,7 @@ function omitDeselectedFields(self, json) {
*
* @param {Object} options
* @param {Boolean} [options.flattenMaps=true] if true, convert Maps to [POJOs](https://masteringjs.io/tutorials/fundamentals/pojo). Useful if you want to `JSON.stringify()` the result.
* @param {Boolean} [options.flattenObjectIds=false] if true, convert any ObjectIds in the result to 24 character hex strings.
* @return {Object}
* @see Document#toObject https://mongoosejs.com/docs/api/document.html#Document.prototype.toObject()
* @see JSON.stringify() in JavaScript https://thecodebarbarian.com/the-80-20-guide-to-json-stringify-in-javascript.html
Expand All @@ -4154,6 +4166,9 @@ Document.prototype.toJSON = function(options) {
return this.$toObject(options, true);
};

/*!
* ignore
*/

Document.prototype.ownerDocument = function() {
return this;
Expand Down
3 changes: 3 additions & 0 deletions lib/helpers/clone.js
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ function clone(obj, options, isArrayChild) {
}

if (isBsonType(obj, 'ObjectId')) {
if (options && options.flattenObjectIds) {
return obj.toJSON();
}
return new ObjectId(obj.id);
}

Expand Down
34 changes: 34 additions & 0 deletions test/document.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -6721,6 +6721,40 @@ describe('document', function() {
assert.equal(mapTest.toObject({}).test.key1.name, 'value1');
});

it('flattenObjectIds option for toObject() (gh-13341) (gh-2790)', function() {
const schema = new Schema({
_id: 'ObjectId',
nested: {
id: 'ObjectId'
},
subdocument: new Schema({}),
documentArray: [new Schema({})]
}, { versionKey: false });

let Test = db.model('Test', schema);

const doc = new Test({
_id: new mongoose.Types.ObjectId('0'.repeat(24)),
nested: {
id: new mongoose.Types.ObjectId('1'.repeat(24))
},
subdocument: {
_id: new mongoose.Types.ObjectId('2'.repeat(24))
},
documentArray: [{ _id: new mongoose.Types.ObjectId('3'.repeat(24)) }]
});
assert.deepStrictEqual(doc.toObject({ flattenObjectIds: true }), {
_id: '0'.repeat(24),
nested: {
id: '1'.repeat(24)
},
subdocument: {
_id: '2'.repeat(24)
},
documentArray: [{ _id: '3'.repeat(24) }]
});
});

it('`collection` property with strict: false (gh-7276)', async function() {
const schema = new Schema({}, { strict: false, versionKey: false });
const Model = db.model('Test', schema);
Expand Down
2 changes: 2 additions & 0 deletions types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,8 @@ declare module 'mongoose' {
versionKey?: boolean;
/** if true, convert Maps to POJOs. Useful if you want to `JSON.stringify()` the result of `toObject()`. */
flattenMaps?: boolean;
/** if true, convert any ObjectIds in the result to 24 character hex strings. */
flattenObjectIds?: boolean;
/** If true, omits fields that are excluded in this document's projection. Unless you specified a projection, this will omit any field that has `select: false` in the schema. */
useProjection?: boolean;
}
Expand Down

0 comments on commit 5d93dff

Please sign in to comment.