;(function () { let backup = context.data const updateLogs = compareAndUpdateEntry(backup?.entry, backup?.collectionName, backup?.versionNr - 1) backup.updateLogs = updateLogs return { data: backup } function compareAndUpdateEntry(entry, collectionName, versionNr) { let updateLogs if (versionNr == 0) { updateLogs = getUpdateLogs({}, entry) } delete entry.updateTime let previousEntry = context.db.find("backups", { filter: { entryId: context.data.entryId, versionNr, collectionName }, })[0] if (!previousEntry) { console.error("No previous entry found") updateLogs = getUpdateLogs({}, entry) } else { delete previousEntry.updateTime updateLogs = getUpdateLogs(previousEntry.entry, entry) } console.log(context.json.stringify(previousEntry?.entry), context.json.stringify(entry)) return updateLogs } function filterValidObjects(array) { return array.filter((object) => { for (let key in object) { if (typeof object[key] !== "string" && object[key] !== null) { return false } } return true }) } function getUpdateLogs(oldObj = {}, newObj = {}, path = "") { let updateLogs = [] const ignoredKeys = ["id", "insertTime", "updateTime"] const allKeys = new Set([...Object.keys(oldObj), ...Object.keys(newObj)]) allKeys.forEach((key) => { if (ignoredKeys.includes(key)) return const newPath = path ? `${path}.${key}` : key const oldVal = oldObj.hasOwnProperty(key) ? oldObj[key] : "" const newVal = newObj.hasOwnProperty(key) ? newObj[key] : "" // Handle Arrays if (Array.isArray(oldVal) || Array.isArray(newVal)) { const oldArr = oldVal || [] const newArr = newVal || [] for (let i = 0; i < Math.max(oldArr.length, newArr.length); i++) { const itemPath = `${newPath}[${i}]` if (oldArr[i] !== newArr[i]) { if (typeof oldArr[i] === "object" || typeof newArr[i] === "object") { const arrUpdates = getUpdateLogs(oldArr[i], newArr[i], itemPath) updateLogs = updateLogs.concat(arrUpdates) } else { updateLogs.push({ field: itemPath, previous: oldArr[i] === undefined ? "" : oldArr[i].toString(), current: newArr[i] === undefined ? "" : newArr[i].toString(), }) } } } } // Handle nested objects but not arrays else if ( (typeof oldVal === "object" && oldVal !== null) || (typeof newVal === "object" && newVal !== null) ) { const nestedUpdates = getUpdateLogs(oldVal || {}, newVal || {}, newPath) updateLogs = updateLogs.concat(nestedUpdates) } // Handle primitive types else if (oldVal !== newVal) { updateLogs.push({ field: newPath, previous: oldVal.toString(), current: newVal.toString(), }) } }) return filterValidObjects(updateLogs) } })()