0

I am trying to pass through an object that looks like this

{ 
    "nodes": [
            {
              "attributes": null
            },
            {
              "attributes": {
                "nodes": [
                  {
                    "attributeId": 1,
                    "name": "pa_color",
                    "options": [
                      "gray"
                    ]
                  },
                  {
                    "attributeId": 2,
                    "name": "pa_size",
                    "options": [
                      "large"
                    ]
                  }
                ]
              }
            },
            {
              "attributes": {
                "nodes": [
                  {
                    "attributeId": 1,
                    "name": "pa_color",
                    "options": [
                      "blue"
                    ]
                  }
                ]
              }
            }
          ]
}

into a react component that renders all the different options under all the unique names. However, the way the data is structured means that I receive duplicates of names and options.

I am trying to convert the object into this object

{ 
    "node": {
        "attributeId": 1,
        "name": "pa_color",
        "values": [
          {
            "name": "gray"
          },
          {
            "name": "blue"
          }
        ]
    },
    "node": {
        "attributeId": 2,
        "name": "pa_size",
        "values": [
          {
            "name": "large"
          }
        ]
    },
}

Current code looks like this

export interface Category_products_edges_node_attributes_edges_node {
  __typename: "ProductAttribute";
  /**
   * Attribute Global ID
   */
  name: string;
  /**
   * Attribute options
   */
  options: (string | null)[] | null;
  /**
   * Attribute ID
   */
  attributeId: number;
}

export interface ProductFiltersProps {
  attributes: Category_products_edges_node_attributes_edges_node[]
}

export const ProductFilters: React.FC<ProductFiltersProps> = ({
  attributes,
}) => (
  <div className="product-filters">
    <div className="container">
      <div className="product-filters__grid">
        {attributes.map(attribute => (

I have tried to do

{groupBy(attributes, 'attributeId').map(attribute => (

With the Lodash library, but receive the error

This expression is not callable. Type 'Category_products_edges_node_attributes_edges_node[]' has no call signatures.

What is the best way to do this?

Thank you

Karan Kiri
  • 316
  • 2
  • 12
Slyds
  • 45
  • 6

1 Answers1

0

lodash groupBy returns an Object not an Array therefore the javascript .map call will not work on it. Also groupBy is used to group items with similar property under one key inside an object, it isn't used to remove duplicates.

To remove duplicates use the lodash uniqBy method. This method can be called on an array and returns an array without duplicates.

Update: To view in more detail how you can remove duplicates based on more than one property of object please see great answer

Also the output object you are trying to achieve has similar keys, I think that is not what you want, a Javascript object should not have duplicate keys. So my output gives keys as node0, node1 instead of node

You can achieve this as follows:

const nodes = {
 nodes: [
  { attributes: null },
  {
   attributes: {
    nodes: [
     { attributeId: 1, name: "pa_color", options: ["gray"] },
     { attributeId: 2, name: "pa_size", options: ["large"] }
    ]
   }
  },
  {
   attributes: {
    nodes: [{ attributeId: 1, name: "pa_color", options: ["blue"] }]
   }
  }
 ]
}

const attributes = []
nodes.nodes.forEach(e => {
 if (e.attributes && Array.isArray(e.attributes.nodes)) {
  attributes.push(...e.attributes.nodes)
 }
})

const uniqueAttributes = _.uniqBy(attributes, (obj) => [obj.attributeId, obj.name, obj.options].join())
const uniqueNodes = uniqueAttributes.map((e, i) => ({ ["node" + i]: e }))

console.log("Unique Nodes: ", uniqueNodes)
<script src="https://cdn.jsdelivr.net/npm/lodash@4.17.10/lodash.min.js"></script>
  • I used a lot of ES6 so do let me know if you don't understand some part of the syntax – Hussain Nawaz Lalee Oct 20 '19 at 07:24
  • thank you for your answer. The result only returns the one 'gray' of the two pa_color options. Is it possible to pass ["attributeId","name","options"] as the argument instead of just "attributeId"? – Slyds Oct 20 '19 at 07:38
  • Yes you can. Check the updated answer I have linked another answer that shows this in great detail – Hussain Nawaz Lalee Oct 20 '19 at 08:04