fix(35): fix rollback incorrectly restoring nested objects when $set targets a dotted path #36
Conversation
There was a problem hiding this comment.
Orca Security Scan Summary
| Status | Check | Issues by priority | |
|---|---|---|---|
| Infrastructure as Code | View in Orca | ||
| SAST | View in Orca | ||
| Secrets | View in Orca | ||
| Vulnerabilities | View in Orca |
|
Hi @pp0rtal 👋 I noticed this issue while reviewing a usage of one of our migration scripts (https://github.com/360Learning/platform/pull/82247#pullrequestreview-4525537020). I've tested in local and that fix allows https://github.com/360Learning/platform/pull/82247 to be unblocked and merged as it is 👍 There is also another similar PR using that script coming soon (cf https://github.com/360Learning/platform/pull/81907#discussion_r3438557511). The long story short is: we ideally would like to have this merged and used by the platform by the release on next week. 😁 I've allowed myself to bump the Feel free to merge if everything looks good to you! |
| rollbackSet[setPropertyKeyStartsWith] = _.get( | ||
| backup, | ||
| setPropertyKeyStartsWith, | ||
| ); |
There was a problem hiding this comment.
@hugop95 Ofc we need lodash for nested support here (like for other cases)
$settargets a dotted path #35This fix, alongside making sure that the platform gets the latest version of
mongo-bulk-data-migration, should ensure that https://github.com/360Learning/platform/pull/82247#pullrequestreview-4525537020 works.Description
When a migration uses
$setwith a dotted path (e.g.'a.b') to overwrite an existing nested object, the rollback restores that field to a wrong value.Instead of restoring the original nested structure, it produces a flat object with a dotted key in the field name:
Why it happened
During rollback,
computeRollbackQueryneeds to figure out what value to$setback for each key the migration changed.For a
$set: { 'a.b': newValue }, the backup stores the full original document (e.g.{ a: { b: { channels: { email: true } } } }). Internally, the backup is flattened into leaf paths for processing, soa.b.channels.email: truebecomes one entry.The bug was in how those leaf paths were reassembled. The code was slicing off the prefix (
a.b) to get the remaining path (channels.email) and using that as a plain JS object key:Instead of looking up the original value directly from the backup: