fix: legacy UUID treatments findable via $or fallback (#6923)

updateIdQuery() and upsertQueryFor() now use
  {$or: [{identifier: UUID}, {_id: UUID}]}
instead of only {identifier: UUID}. This matches both:
- New documents (UUID in identifier field, ObjectId in _id)
- Legacy documents (UUID directly in _id, no identifier field)

Gated behind env.uuidHandling (UUID_HANDLING env var, default true).

All 30 treatment tests pass:
- 3 legacy UUID tests (issue-6923): DELETE, PUT, GET all work
- 12 gap-treat-012 tests: new data paths unaffected
- 15 uuid-handling tests: edge cases, UUID_HANDLING=false still works

Fixes #6923 (unable to edit/save/delete overrides for legacy data)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Ben West
2026-03-25 15:20:51 -07:00
co-authored by Copilot
parent 98ee2bcb3e
commit 246e46adb3
3 changed files with 14 additions and 7 deletions
+3 -2
View File
@@ -100,8 +100,9 @@ function updateIdQuery (query, opts) {
if (typeof query._id === 'string') { if (typeof query._id === 'string') {
var result = normalizeIdValue(query._id, opts); var result = normalizeIdValue(query._id, opts);
if (result.searchByIdentifier) { if (result.searchByIdentifier) {
// UUID detected with uuidHandling enabled - search by identifier instead // UUID detected with uuidHandling enabled
query.identifier = result.value; // Use $or to match both new docs (identifier field) and legacy docs (UUID in _id)
query.$or = [{ identifier: result.value }, { _id: result.value }];
delete query._id; delete query._id;
} else { } else {
query._id = result.value; query._id = result.value;
+6 -1
View File
@@ -320,8 +320,13 @@ function storage (env, ctx) {
if (obj.identifier) { if (obj.identifier) {
// Remove _id from replacement - MongoDB will use existing _id on update, // Remove _id from replacement - MongoDB will use existing _id on update,
// or generate new one on insert // or generate new one on insert
var identifierValue = obj.identifier;
delete obj._id; delete obj._id;
return { identifier: obj.identifier }; // Use $or to match both new docs (identifier field) and legacy docs (UUID in _id)
if (env.uuidHandling) {
return { $or: [{ identifier: identifierValue }, { _id: identifierValue }] };
}
return { identifier: identifierValue };
} }
// 2. Fall back to _id if present and valid // 2. Fall back to _id if present and valid
if (Object.prototype.hasOwnProperty.call(obj, '_id') && obj._id !== null && obj._id !== '') { if (Object.prototype.hasOwnProperty.call(obj, '_id') && obj._id !== null && obj._id !== '') {
+5 -4
View File
@@ -1,7 +1,7 @@
'use strict'; 'use strict';
/** /**
* Legacy UUID Data Test: Issue #6923 Reproduction * Legacy UUID Data Test: Issue #6923 Regression
* *
* ISSUE: https://github.com/nightscout/cgm-remote-monitor/issues/6923 * ISSUE: https://github.com/nightscout/cgm-remote-monitor/issues/6923
* *
@@ -11,10 +11,11 @@
* *
* The test inserts a legacy-shaped document directly into MongoDB * The test inserts a legacy-shaped document directly into MongoDB
* (bypassing normalizeTreatmentId) and then exercises the API * (bypassing normalizeTreatmentId) and then exercises the API
* DELETE and PUT paths that a user would trigger from Reports > Treatments. * DELETE, PUT, and GET paths that a user would trigger from Reports > Treatments.
* *
* EXPECTED RESULT: These tests FAIL, proving the legacy data bug. * FIX: updateIdQuery() and upsertQueryFor() now use $or to match both
* When all tests pass, the bug is fixed. * {identifier: UUID} (new docs) and {_id: UUID} (legacy docs).
* All 3 tests pass, confirming Loop can manage pre-existing overrides.
*/ */
const request = require('supertest'); const request = require('supertest');