Search code examples
javascriptnode.jsunique

Compare two json objects and append unique items


I have two JSON files - one fetched from the server (data), the other is local (database).

I'm trying to loop through the server json, compare it to the local json, and then append any new objects to the local file. This way when the script runs a second time, those new items have been appended and can be skipped.

Problem:

Currently when it runs after the initial time, because it checks a-a, a-b, a-c, b-a, b-b, b-c... it will skip the initial results, but then add in the other options.

The js Im using:

let additions = [];
data.forEach(item1 => {
  database.filter(item2 => {
    if( !(item1.value === item2.value && item1.country === item2.country) ) {
      additions.push(item1)
    }
  })
});

Example / expectations:

data = [
  { value: "qwert", country: "US" },
  { value: "asdfg", country: "CA" },
  { value: "zxcvb", country: "GB" }
] 

database = [
  { value: "poiuy", country: "CA" },
  { value: "qwert", country: "US" }
]

Then after the looping and checking, it would result in the following (initial run):

output = [
  { value: "poiuy", country: "CA" },
  { value: "qwert", country: "US" },
  { value: "asdfg", country: "CA" },
  { value: "zxcvb", country: "GB" }
] 

When I run the loop the next time, if the data has changed:

data = [
  { value: "poiuy", country: "CA" },
  { value: "wsxcd", country: "AU" },
  { value: "rfvbg", country: "NZ" },
  { value: "zxcvb", country: "FR" }
]

I am expecting this:

output = [
  { value: "poiuy", country: "CA" },
  { value: "qwert", country: "US" },
  { value: "asdfg", country: "CA" },
  { value: "zxcvb", country: "GB" },
  { value: "wsxcd", country: "AU" },
  { value: "rfvbg", country: "NZ" },
  { value: "zxcvb", country: "FR" }
]

But I am receiving this:

output = [
  { value: "poiuy", country: "CA" },
  { value: "qwert", country: "US" },
  { value: "asdfg", country: "CA" },
  { value: "zxcvb", country: "GB" },
  { value: "poiuy", country: "CA" },
  { value: "poiuy", country: "CA" },
  { value: "poiuy", country: "CA" },
  { value: "wsxcd", country: "AU" },
  { value: "wsxcd", country: "AU" },
  { value: "wsxcd", country: "AU" },
  { value: "rfvbg", country: "NZ" },
  { value: "rfvbg", country: "NZ" },
  { value: "rfvbg", country: "NZ" },
  { value: "zxcvb", country: "FR" },
  { value: "zxcvb", country: "FR" },
  { value: "zxcvb", country: "FR" }
]

Any help would be appreciated as I can't seem to figure it out so that it will append the items only unique, and not for item to item.


Solution

  • You can use array#reduce to get unique value based on value and country in an object accumulator. Then get all values from these object using Object.values().

    const localData = [ { value: "qwert", country: "US" }, { value: "asdfg", country: "CA" }, { value: "zxcvb", country: "GB" }],
          database = [{ value: "poiuy", country: "CA" }, { value: "qwert", country: "US" }],
          getUnique = (arr1, arr2) => Object.values([...arr1, ...arr2].reduce((r,o) => {
            const key = `${o.value}_${o.country}`;
            r[key] ??= o;
            return r;
          },{}));
    console.log(getUnique(localData, database));