Home > Back-end >  Merge objects in array by unique product name
Merge objects in array by unique product name

Time:06-29

I have object like that

const testOb = {
  ReleaseName: "latest",
  Products: [
    {
      ProductName: "WIDG",
      A6Product: true,
      ProductVersions: ["15.0.0"],
    },
    {
      ProductName: "BIS",
      A12Product: true,
      ProductVersions: ["21.0.0"],
    },
    {
      ProductName: "WIDG",
      A6Product: true,
      ProductVersions: ["11.0.0"],
    },
    {
      ProductName: "BIS",
      A6Product: true,
      ProductVersions: ["15.0.0"],
    },
    {
      ProductName: "UAB",
      A12Product: true,
      ProductVersions: ["15.0.0"],
    },
    {
      ProductName: "UAB",
      A12Product: true,
      ProductVersions: ["1.0.0"],
    },
    {
      ProductName: "WIDG",
      A6Product: true,
      ProductVersions: ["6.0.0"],
    },
    {
      ProductName: "BIS",
      A6Product: true,
      ProductVersions: ["7.0.0"],
    }
  ],
};

in result I want to get object like that

const testOb = {
  ReleaseName: "latest",
  Products: [
    {
      ProductName: "WIDG",
      A6Product: true,
      ProductVersions: ["15.0.0"],
    },
    {
      ProductName: "BIS",
      A12Product: true,
      ProductVersions: ["21.0.0"],
    },
    {
      ProductName: "UAB",
      A12Product: true,
      ProductVersions: ["15.0.0"],
    }
  ],
};

Essentially I want to keep the unique objects in array and copy there the latest version of unique product name. I have tried looking at lodash as well and have not been able to come up with a way to do it. Any help would be much appreciated!

CodePudding user response:

You could compare the version with String#localeCompare with options.

const
    isSmaller = (a, b) => a
        .toString()
        .localeCompare(b, undefined, { numeric: true, sensitivity: 'base' }) < 0,
    products = [{ ProductName: "WIDG", A6Product: true, ProductVersions: ["15.0.0"] }, { ProductName: "BIS", A12Product: true, ProductVersions: ["21.0.0"] }, { ProductName: "WIDG", A6Product: true, ProductVersions: ["11.0.0"] }, { ProductName: "BIS", A6Product: true, ProductVersions: ["15.0.0"] }, { ProductName: "UAB", A12Product: true, ProductVersions: ["15.0.0"] }, { ProductName: "UAB", A12Product: true, ProductVersions: ["1.0.0"] }, { ProductName: "WIDG", A6Product: true, ProductVersions: ["6.0.0"] }, { ProductName: "BIS", A6Product: true, ProductVersions: ["7.0.0"] }],
    latests = Object.values(products.reduce((r, o) => {
        if (
            !r[o.ProductName] ||
            isSmaller(r[o.ProductName].ProductVersions, o.ProductVersions)                
        ) r[o.ProductName] = o;
        return r;
    }, {}));

console.log(latests);
.as-console-wrapper { max-height: 100% !important; top: 0; }

CodePudding user response:

You will need to devise a comparator for version numbers. Once you have that, you can reduce the products by keying on the name, comparing the existing to the current, and finally updating if the new version is larger.

const compareVersions = (a, b) => {
  const [aMaj, aMin, aPat] = a.split('\\.').map(parseInt);
  const [bMaj, bMin, bPat] = b.split('\\.').map(parseInt);
  return aMaj - bMaj || aMin - bMin || aPat - bPat;
}

const compareProducts = (a, b) =>
  compareVersions(a.ProductVersions[0], b.ProductVersions[0]);

const testOb = {
  ReleaseName: "latest",
  Products: [
    { ProductName: "WIDG" , A6Product:  true , ProductVersions: ["15.0.0"] },
    { ProductName: "BIS"  , A12Product: true , ProductVersions: ["21.0.0"] },
    { ProductName: "WIDG" , A6Product:  true , ProductVersions: ["11.0.0"] },
    { ProductName: "BIS"  , A6Product:  true , ProductVersions: ["15.0.0"] },
    { ProductName: "UAB"  , A12Product: true , ProductVersions: ["15.0.0"] },
    { ProductName: "UAB"  , A12Product: true , ProductVersions: ["1.0.0"]  },
    { ProductName: "WIDG" , A6Product:  true , ProductVersions: ["6.0.0"]  },
    { ProductName: "BIS"  , A6Product:  true , ProductVersions: ["7.0.0"]  }
  ],
};

const latest = {
  ...testOb,
  Products: Object.values(testOb.Products.reduce((acc, product) =>
    (existing =>
      !existing || (existing && compareProducts(existing, product) < 0)
        ? { ...acc, [product.ProductName]: product }
        : acc)
    (acc[product.ProductName]), {}))
};

console.log(latest);
.as-console-wrapper { top: 0; max-height: 100% !important; }

  • Related