From 316c54bd7dc52a130e274b08a2d8a742ec0cbd08 Mon Sep 17 00:00:00 2001 From: Valeri Karpov Date: Sun, 11 Sep 2022 19:53:17 -0400 Subject: [PATCH] fix(array): apply fix for #12294 to nested paths --- lib/types/array/methods/index.js | 39 +++++++++++++++++++++++++++++++- test/types.array.test.js | 3 +++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/lib/types/array/methods/index.js b/lib/types/array/methods/index.js index 61f7b10d7d7..12c2f611d1c 100644 --- a/lib/types/array/methods/index.js +++ b/lib/types/array/methods/index.js @@ -5,6 +5,7 @@ const ArraySubdocument = require('../../ArraySubdocument'); const MongooseError = require('../../../error/mongooseError'); const cleanModifiedSubpaths = require('../../../helpers/document/cleanModifiedSubpaths'); const internalToObjectOptions = require('../../../options').internalToObjectOptions; +const mpath = require('mpath'); const utils = require('../../../utils'); const isBsonType = require('../../../helpers/isBsonType'); @@ -349,7 +350,9 @@ const methods = { } Object.keys(v.$__.activePaths.getStatePaths('default')).forEach(path => { - delete ret[path]; + mpath.unset(path, ret); + + _minimizePath(ret, path); }); return ret; @@ -937,6 +940,40 @@ function _isAllSubdocs(docs, ref) { return true; } +/*! + * Minimize _just_ empty objects along the path chain specified + * by `parts`, ignoring all other paths. Useful in cases where + * you want to minimize after unsetting a path. + * + * #### Example: + * + * const obj = { foo: { bar: { baz: {} } }, a: {} }; + * _minimizePath(obj, 'foo.bar.baz'); + * obj; // { a: {} } + */ + +function _minimizePath(obj, parts, i) { + if (typeof parts === 'string') { + if (parts.indexOf('.') === -1) { + return; + } + + parts = mpath.stringToParts(parts); + } + i = i || 0; + if (i >= parts.length) { + return; + } + if (obj == null || typeof obj !== 'object') { + return; + } + + _minimizePath(obj[parts[0]], parts, i + 1); + if (obj[parts[0]] != null && typeof obj[parts[0]] === 'object' && Object.keys(obj[parts[0]]).length === 0) { + delete obj[parts[0]]; + } +} + /*! * ignore */ diff --git a/test/types.array.test.js b/test/types.array.test.js index 8aef5ed7043..19b337c36b1 100644 --- a/test/types.array.test.js +++ b/test/types.array.test.js @@ -829,6 +829,9 @@ describe('types array', function() { colors: [{ _id: false, hex: { type: String, default: '#ffffff' }, + properties: { + hue: { type: Number, default: 0 } + }, name: String }] });