У меня есть два файла JSON, полученные из приложения.
Мне нужно сравнить их на предмет изменений и создать отчет об изменениях.
В основном я могу это сделать, но у меня возникли проблемы с созданием отчета об измененных вложенных объектах внутри объекта.
Я вижу, что объекты изменились, и могу отправить оба объекта целиком. Моя проблема в том, что некоторые из них могут иметь десятки или даже сотни пар ключ-значение, и трудно определить, какие записи объектов были изменены.
Как сравнить два файла JSON с желаемой структурой отчета (показанной ниже) для сопоставления объектов с вложенными объектами двух файлов JSON?
два объекта из каждого файла совпадают, если их ids
совпадают.
В моем примере есть одна совпадающая пара объектов с вложенным объектом options
, сектор/сектор2, но может существовать и несколько совпадающих пар.
(мои извинения за весь код)
Для удобства я создал лист Google со всем кодом. https://docs.google.com/spreadsheets/d/1G2c1qsBvW5rW9Z0yRbF6OhBkw8cZ7U5XHY0Ab0u2z-M/edit?usp=sharing
Спасибо
let oldJSON = [
{
"id": "c3c6f410f58e5836431b473ebcf134756232d04f2bf35edff8",
"label": "Sector2",
"options": {
"62f92fab79ac81d933765bd0bbc4a1f5ea26cb3a088bcb4e6e": {
"index": 0,
"value": "Bob",
"label": "Bob"
},
"2fe91aa3567c0d04c521dcd2fc7e40d7622bb8c3f594d503da": {
"index": 1,
"value": "Student",
"label": "Student"
},
"c59ea1159f33b91a7f6edc6925be5e373fc543e4": {
"index": 2,
"value": "BBB",
"label": "BBB"
},
"c59ea1159f33b91a7f6edc6925be5e373fc54AAA": {
"index": 3,
"value": "Orange Duck",
"label": "Orange Duck"
}
}
},
{
"id": "f794c6a52e793ee6f5c42cd5df6b4435236e3495e951709485",
"label": "Brown Cow"
},
{
"id": "f794c6a52e793ee6f5c42cd5df6b4435236e3495e95170ZZZ",
"label": "Red Fish"
},
];
let newJSON = [
{
"id": "f794c6a52e793ee6f5c42cd5df6b4435236e3495e951709485",
"label": "Green Frog"
},
{
"id": "c3c6f410f58e5836431b473ebcf134756232d04f2bf35edff8",
"label": "Sector",
"options": {
"62f92fab79ac81d933765bd0bbc4a1f5ea26cb3a088bcb4e6e": {
"index": 0,
"value": "Bob",
"label": "Bob"
},
"c59ea1159f33b91a7f6edc6925be5e373DDDDDDDDD": {
"index": 1,
"value": "GrassLand",
"label": "TreeLand"
},
"2fe91aa3567c0d04c521dcd2fc7e40d7622bb8c3f594d503da": {
"index": 2,
"value": "Student",
"label": "Student"
},
"c59ea1159f33b91a7f6edc6925be5e373fc543e4": {
"index": 3,
"value": "AAA",
"label": "AAA"
}
}
},
{
"id": "f794c6a52e793ee6f5c42cd5df6b4435236e3495e951709AAA",
"label": "Blue Bird"
}
];
Мой код на данный момент
// Create an object to store the results of the comparison.
const results = {};
// Loop through the first array.
for (const item1 of array1) {
// Check if the item exists in the second array.
let item2 = array2.find(item => item.id === item1.id);
// If the item does not exist in the second array, add it to the results object as a deleted item.
if (!item2) {
results.deleted = results.deleted || [];
results.deleted.push(item1);
} else {
// If the item exists in the second array, compare the two objects.
const differences = compareObjects(item1, item2);
// If there are any differences, add the item to the results object as a changed item.
if (Object.keys(differences).length > 0) {
results.changed = results.changed || [];
let
label1 = item1.label,
label2 = item2.label;
results.changed.push({
label1,
label2,
differences,
});
}
}
}
// Loop through the second array.
for (const item2 of array2) {
// Check if the item exists in the first array.
const item1 = array1.find(item => item.id === item2.id);
// If the item does not exist in the first array, add it to the results object as an added item.
if (!item1) {
results.added = results.added || [];
results.added.push(item2);
}
}
// Return the results object.
return results;
}
function compareObjects(object1, object2) {
// Create an object to store the differences between the two objects.
const differences = {};
// Loop through the keys of the first object.
for (const key of Object.keys(object1)) {
// Get the value of the key in the second object.
const value2 = object2[key];
// If the value does not exist in the second object, add it to the differences object as a deleted value.
if (value2 === undefined) {
differences[key] = {
value1: object1[key],
value2: undefined,
};
} else {
// If the value exists in the second object, compare the two values.
if (object1[key] !== value2) {
differences[key] = {
value1: object1[key],
value2,
};
}
}
}
// Loop through the keys of the second object.
for (const key of Object.keys(object2)) {
// Check if the key exists in the first object.
if (!object1.hasOwnProperty(key)) {
// If the key does not exist in the first object, add it to the differences object as an added value.
differences[key] = {
value1: undefined,
value2: object2[key],
};
}
}
// Return the differences object.
return differences;
}
Результат, который я получаю
{
"changed": [
{
"label1": "Sector2",
"label2": "Sector",
"differences": {
"label": {
"value1": "Sector2",
"value2": "Sector"
},
"options": {
"value1": {
"62f92fab79ac81d933765bd0bbc4a1f5ea26cb3a088bcb4e6e": {
"index": 0,
"value": "Bob",
"label": "Bob"
},
"2fe91aa3567c0d04c521dcd2fc7e40d7622bb8c3f594d503da": {
"index": 1,
"value": "Student",
"label": "Student"
},
"c59ea1159f33b91a7f6edc6925be5e373fc543e4": {
"index": 2,
"value": "BBB",
"label": "BBB"
},
"c59ea1159f33b91a7f6edc6925be5e373fc54AAA": {
"index": 3,
"value": "Orange Duck",
"label": "Orange Duck"
}
},
"value2": {
"62f92fab79ac81d933765bd0bbc4a1f5ea26cb3a088bcb4e6e": {
"index": 0,
"value": "Bob",
"label": "Bob"
},
"c59ea1159f33b91a7f6edc6925be5e373DDDDDDDDD": {
"index": 1,
"value": "GrassLand",
"label": "TreeLand"
},
"2fe91aa3567c0d04c521dcd2fc7e40d7622bb8c3f594d503da": {
"index": 2,
"value": "Student",
"label": "Student"
},
"c59ea1159f33b91a7f6edc6925be5e373fc543e4": {
"index": 3,
"value": "AAA",
"label": "AAA"
}
}
}
}
},
{
"label1": "Brown Cow",
"label2": "Green Frog",
"differences": {
"label": {
"value1": "Brown Cow",
"value2": "Green Frog"
}
}
}
],
"deleted": [
{
"id": "f794c6a52e793ee6f5c42cd5df6b4435236e3495e95170ZZZ",
"label": "Red Fish"
}
],
"added": [
{
"id": "f794c6a52e793ee6f5c42cd5df6b4435236e3495e951709AAA",
"label": "Blue Bird"
}
]
}
Желаемый результат или что-то эквивалентное
{
"changed": [
{
"label1": "Sector2",
"label2": "Sector",
"differences": {
"label": {
"value1": "Sector2",
"value2": "Sector"
},
"options": {
"value1": {
"c59ea1159f33b91a7f6edc6925be5e373fc54AAA": {
"deleted": {
"index": 3,
"value": "Orange Duck",
"label": "Orange Duck"
}
}
},
"value2": {
"added":{
"c59ea1159f33b91a7f6edc6925be5e373DDDDDDDDD": {
"index2": 1,
"value": "GrassLand",
"label": "TreeLand"
}
},
"2fe91aa3567c0d04c521dcd2fc7e40d7622bb8c3f594d503da": {
"changed": {
"index1": 1,
"index2": 2,
"value1": "Student",
"value2": "Student",
"label1": "Student",
"label2": "Student"
}
},
"c59ea1159f33b91a7f6edc6925be5e373fc543e4": {
"changed": {
"index1": 2,
"index2": 3,
"value1": "BBB",
"value2": "AAA",
"label1": "BBB",
"label2": "AAA"
}
}
}
}
}
},
{
"label1": "Brown Cow",
"label2": "Green Frog",
"differences": {
"label": {
"value1": "Brown Cow",
"value2": "Green Frog"
}
}
}
],
"deleted": [
{
"id": "f794c6a52e793ee6f5c42cd5df6b4435236e3495e95170ZZZ",
"label": "Red Fish"
}
],
"added": [
{
"id": "f794c6a52e793ee6f5c42cd5df6b4435236e3495e951709AAA",
"label": "Blue Bird"
}
]
}
Я делаю это в Google Sheets. Не я не уверен, что это можно сделать в Google Sheets.
Это дает отчет, который отражает суть того, что вы спросили. вывод немного другой
function compareJSONs(oldJSON,newJSON) {
// Create an object to store the results of the comparison
let
results = {
deleted: [],
added: [],
changed: []
};
// Loop through the old JSON array
for (const oldObj of oldJSON) {
// Find the matching object in the new JSON array
const newObj = newJSON.find(newItem => newItem.id === oldObj.id);
if (!newObj) {
// Object exists in oldJSON but not in newJSON (deleted)
results.deleted.push(oldObj);
}
else {
// Compare nested options
let changedOptions = {};
for (const key in oldObj.options) {
if (newObj.options[key] !== oldObj.options[key]) {
changedOptions[key] = {
oldValue: oldObj.options[key],
newValue: newObj.options[key]
};
};
};
for (const key in newObj.options) {
//console.info(newObj.options[key])
if (newObj.options[key] !== oldObj.options[key]) {
changedOptions[key] = {
oldValue: oldObj.options[key],
newValue: newObj.options[key]
};
};
};
//Remove objects where keys have identical value (all the NON-changed options)
for (const key in changedOptions) {
const {oldValue: a, newValue: b} = changedOptions[key];
a?.index === b?.index && a?.value === b?.value && a?.label === b?.label && delete changedOptions[key];
};
if (Object.keys(changedOptions).length > 0) {
// Object exists in both oldJSON and newJSON, with changes
results.changed.push({
id: newObj.id,
oldLabel: oldObj.label,
newLabel: newObj.label,
changedOptions
});
};
};
};
// Check for added objects
for (const newObj of newJSON) {
if (!oldJSON.find(oldItem => oldItem.id === newObj.id)) {
results.added.push(newObj);
};
};
return results;
}
Обновлено:
Если вам нужна структура, которую вы опубликовали, используйте следующее после compareJSONs
function mergOBJ(data) {
const transformedData = { ...data }; // Create a copy to avoid mutation
transformedData.ChangedObjects.changedOptions = Object.entries(data.ChangedObjects.changedOptions).reduce((acc, [key, value]) => {
console.info(value.oldValue)
if (value.oldValue!==undefined && value.newValue!==undefined){
acc[key] = {
optionChanged: {
oldIndex: value.oldValue.index,
newIndex: value.newValue.index,
oldValue: value.oldValue.value,
newValue: value.newValue.value,
oldLabel: value.oldValue.label,
newLabel: value.newValue.label,
},
}
}else if (value.oldValue===undefined && value.newValue) {
acc[key] = {
optionAdded: {
index: value.newValue.index,
value: value.newValue.value,
label: value.newValue.label,
},
}
}else if (value.oldValue && value.newValue===undefined) {
acc[key] = {
optionDeleted: {
index: value.oldValue.index,
value: value.oldValue.value,
label: value.oldValue.label,
},
}
};
return acc;
}, {});
return transformedData;
}
Используйте как:
let Changed = {"ChangedObjects":results.changed[0]}
console.info( JSON.stringify(Изменено, ноль,1))
const mergedReport =mergOBJ(Изменено);
console.info(JSON.stringify(mergedReport, null, 1));
{
"ChangedObjects": {
"id": "c3c6f410f58e5836431b473ebcf134756232d04f2bf35edff8",
"oldLabel": "Sector2",
"newLabel": "Sector",
"changedOptions": {
"2fe91aa3567c0d04c521dcd2fc7e40d7622bb8c3f594d503da": {
"optionChanged": {
"oldIndex": 1,
"newIndex": 2,
"oldValue": "Student",
"newValue": "Student",
"oldLabel": "Student",
"newLabel": "Student"
}
},
"c59ea1159f33b91a7f6edc6925be5e373fc543e4": {
"optionChanged": {
"oldIndex": 2,
"newIndex": 3,
"oldValue": "BBB",
"newValue": "AAA",
"oldLabel": "BBB",
"newLabel": "AAA"
}
},
"c59ea1159f33b91a7f6edc6925be5e373fc54AAA": {
"optionDeleted": {
"index": 3,
"value": "Orange Duck",
"label": "Orange Duck"
}
},
"c59ea1159f33b91a7f6edc6925be5e373DDDDDDDDD": {
"optionAdded": {
"index": 1,
"value": "GrassLand",
"label": "TreeLand"
}
}
}
}
}
Да, это очень хорошо работает! Спасибо, очень ценно!
Вау, это здорово, хотелось бы проголосовать за это еще раз
Я думал, что использовал npmjs.com/package/deep-diff и npmjs.com/package/deep-diff-object для отладки. Те сообщат о различиях. Или логику нужно писать самому?/