1

I'm trying to destructure a JSON file that looks like this:

[
  {
    "Bags": [
      {
        "id": 1,
        "name": "Michael Kors Bag",
        "price": 235,
        "imgURL": "/imgs/03045643da82a42a4a5c86842f4b17f1.jpg"
      },
      {
        "id": 2,
        "name": "Ted Baker Bag",
        "price": 495,
        "imgURL": "/imgs/4c176b2fa86bdcddf74822c2501bbcac.jpg"
      },
      {
        "id": 3,
        "name": "Coach Bag",
        "price": 238,
        "imgURL": "/imgs/coach-jes-crossbody-signature-canvas-brown-black-59181.jpg"
      },
      {
        "id": 4,
        "name": "Kate Spade Bag",
        "price": 35,
        "imgURL": "/imgs/10.jpg"
      }
    ]
  },
  {
    "Shoes": [
      {
        "id": 1,
        "name": "Michael Kors Bag",
        "price": 235,
        "imgURL": "/imgs/03045643da82a42a4a5c86842f4b17f1.jpg"
      },
      {
        "id": 2,
        "name": "Ted Baker Bag",
        "price": 495,
        "imgURL": "/imgs/4c176b2fa86bdcddf74822c2501bbcac.jpg"
      },
      {
        "id": 3,
        "name": "Coach Bag",
        "price": 238,
        "imgURL": "/imgs/coach-jes-crossbody-signature-canvas-brown-black-59181.jpg"
      },
      {
        "id": 4,
        "name": "Kate Spade Bag",
        "price": 35,
        "imgURL": "/imgs/10.jpg"
      }
    ]
  }
]

So that I get the name of the objects ("Bags" and "Shoes").

I'm trying to print out the results on a page based on which is which and I'm feeding in the names as strings to a Store component like so:

<Route path="/store" element={<Store merch="Bags" />} />

This is my Store.tsx file, it doesn't work at all but it's my attempt:

import storeItems from "../data/items.json";
import { Row, Col, Container } from "react-bootstrap";
import { StoreItem } from "../components/StoreItem";
import { useState } from "react";

type StoreProps = {
  merch: string;
};

export function Store({ merch }: StoreProps) {
  const [data, setData] = useState([]);
  for (let i = 0; i < storeItems.length; i++) {
    let a = Object.values(storeItems[i]);
    console.log(a);
  }
  console.log(storeItems);
  return (
    <>
      <Container className="mw-80 d-flex align-items-center justify-content-center p-0 flex-column mb-5">
        <h1 className="m-5">Bags</h1>
        <Row md={2} xs={1} lg={3} className="g-3">
          {storeItems.map((item) => (
            <Col>
              <StoreItem key={item.id} {...item} />
            </Col>
          ))}
        </Row>
      </Container>
    </>
  );
}

4 Answers 4

3

In order to get ["Bags", "Shoes"] from your storeItems you could:

const names = storeItems.flatMap(mi => Object.keys(mi));

This would get additional keys on the same object as well, so if you had:

const storeItems = [
    { "Bags": /*...*/{}, "Bags2": /*...*/{}, },
    { "Shoes": /*...*/{} },
];

then it would return [ "Bags", "Bags2", "Shoes" ]

I have to say, your data is in a pretty strange format, but I answered the question exactly as written

Also, if you want the names of all of the objects in a list, as in the name property of each object you could do something like:

const names = storeItems.flatMap(storeItem =>
    Object
        .values(storeItem)
        .flatMap(itemList => itemList.map(item => item.name))
);

Also, if you want the names of all of the objects in the keys of an object by the name (like "Bags", or "Shoes") then you could:

const names = Object.fromEntries(storeItems.flatMap(storeItem => 
    Object.entries(storeItem)
).map([k,v] => [k,v.map(i => i.name)]))

I'm not quite sure which one of these you wanted, so I included all of them (:

Edit

Looking at your code it seems as if you want to get a specific section of the data. This could be done by something like this:

const name = "Shoes";
const items = storeItems.flatMap(si => Object.entries(si))[name]

or if you know that your data is going to always have shoes first and be in the exact format then you could just do

const name = "Shoes";
const items = storeItems[1]["Shoes"];
Sign up to request clarification or add additional context in comments.

2 Comments

But now I think about it, maybe it's my json data that's faulty. I just want a collection of arrays that are named. Maybe my format for the data is wrong. I want to be able to search through the sortItems array for a specific key word and display all items in that key words array.
It sounds like you don't have a backend yet and you're experimenting with a frontend that using a static JSON file for data. Is that correct? It's better to build out the backend first. I would recommend using Next.js since you're already using React. You could easily set up some API routes. Even if the data is hard-coded at first, at least it would help you figure out what your API will look like. If setting up a DB is slightly out of your comfort zone, Supabase makes it quite easy. Supabase is using PostgreSQL, so you can always take your data and go to another PostgreSQL setup. HTH
1

Is this what you're trying to do?

const products = [
  {
    "Bags": [
      {
        "id": 1,
        "name": "Michael Kors Bag",
        "price": 235,
        "imgURL": "/imgs/03045643da82a42a4a5c86842f4b17f1.jpg"
      },
      {
        "id": 2,
        "name": "Ted Baker Bag",
        "price": 495,
        "imgURL": "/imgs/4c176b2fa86bdcddf74822c2501bbcac.jpg"
      },
      {
        "id": 3,
        "name": "Coach Bag",
        "price": 238,
        "imgURL": "/imgs/coach-jes-crossbody-signature-canvas-brown-black-59181.jpg"
      },
      {
        "id": 4,
        "name": "Kate Spade Bag",
        "price": 35,
        "imgURL": "/imgs/10.jpg"
      }
    ]
  },
  {
    "Shoes": [
      {
        "id": 1,
        "name": "Michael Kors Bag",
        "price": 235,
        "imgURL": "/imgs/03045643da82a42a4a5c86842f4b17f1.jpg"
      },
      {
        "id": 2,
        "name": "Ted Baker Bag",
        "price": 495,
        "imgURL": "/imgs/4c176b2fa86bdcddf74822c2501bbcac.jpg"
      },
      {
        "id": 3,
        "name": "Coach Bag",
        "price": 238,
        "imgURL": "/imgs/coach-jes-crossbody-signature-canvas-brown-black-59181.jpg"
      },
      {
        "id": 4,
        "name": "Kate Spade Bag",
        "price": 35,
        "imgURL": "/imgs/10.jpg"
      }
    ]
  }
]

const getProductsByKey = key => products
    .filter(product => product.hasOwnProperty([key]))
    .flatMap(obj => obj[key])

console.log(getProductsByKey('Shoes'))

The output of the above code would be:

[
  {
    id: 1,
    name: 'Michael Kors Bag',
    price: 235,
    imgURL: '/imgs/03045643da82a42a4a5c86842f4b17f1.jpg'
  },
  {
    id: 2,
    name: 'Ted Baker Bag',
    price: 495,
    imgURL: '/imgs/4c176b2fa86bdcddf74822c2501bbcac.jpg'
  },
  {
    id: 3,
    name: 'Coach Bag',
    price: 238,
    imgURL: '/imgs/coach-jes-crossbody-signature-canvas-brown-black-59181.jpg'
  },
  { id: 4, name: 'Kate Spade Bag', price: 35, imgURL: '/imgs/10.jpg' }
]

Please note that the supplied data is incorrect as the items under the key "Shoes" are apparently bags.

I'll explain the why and how of my code. First off, I wanted to make a function that could take any key as an argument. Today we have 'Bags' and 'Shoes', but tomorrow we may have more keys. Therefore, I didn't want to propose a solution that would involve "hard-coded" keys.

Once we have the key, we can use Array.prototype.filter to find the object containing the items we want. In the data we are provided with, 'Bags' and 'Shoes' are keys, not values. Hence why I used product.hasOwnProperty([key]) in the callbackFn. Note the use of the square brackets as we are searching for the value of a dynamic variable named key, not the actual string 'key'. Next we use Array.protoype.flatMap to get to the part of each object that we want, which is the array of items. We use .flapMap here to avoid the nested array that would normally result by chaining filter and map to the data.

3 Comments

Using Object.hasOwnProperty is quite a clever way of doing that! I would have used flatMap with Object.entries.
@Zachiah .flatMap() is a great idea. I'm going to update my anwser to include that. Thank you for reminding me about that!
Describe how and why your answer works, or else it is not useful to future visitors to the site.
0

For getting the shoes you can use this:

storeItems[1]["shoes"]

And for getting the bags you can use this:

storeItems[0]["bags"]

So, in the return expression in your attempt code, instead of this:

return (
<>
  <Container className="mw-80 d-flex align-items-center justify-content-center p-0 flex-column mb-5">
    <h1 className="m-5">Bags</h1>
    <Row md={2} xs={1} lg={3} className="g-3">
      {storeItems.map((item) => (
        <Col>
          <StoreItem key={item.id} {...item} />
        </Col>
      ))}
    </Row>
  </Container>
</>);

use this (for bags):

return (
<>
  <Container className="mw-80 d-flex align-items-center justify-content-center p-0 flex-column mb-5">
    <h1 className="m-5">Bags</h1>
    <Row md={2} xs={1} lg={3} className="g-3">
      {storeItems[0]["bags"].map((item) => (
        <Col>
          <StoreItem key={item.id} {...item} />
        </Col>
      ))}
    </Row>
  </Container>
</>);

2 Comments

How would I loop over every array item? I don't want to hard code the words "bags" and "shoes".
I think using .flatMap can solve it if you don't want to use hardcoded strings in your code.
0

You can use:

  1. a combination of Array.map and Object.keys to get an array with available categories from storeItems object
  2. Array.find to get the products for a given merch category.

const storeItems = [
  {
    "Bags": [
      {
        "id": 1,
        "name": "Michael Kors Bag",
        "price": 235,
        "imgURL": "/imgs/03045643da82a42a4a5c86842f4b17f1.jpg"
      },
      {
        "id": 2,
        "name": "Ted Baker Bag",
        "price": 495,
        "imgURL": "/imgs/4c176b2fa86bdcddf74822c2501bbcac.jpg"
      },
      {
        "id": 3,
        "name": "Coach Bag",
        "price": 238,
        "imgURL": "/imgs/coach-jes-crossbody-signature-canvas-brown-black-59181.jpg"
      },
      {
        "id": 4,
        "name": "Kate Spade Bag",
        "price": 35,
        "imgURL": "/imgs/10.jpg"
      }
    ]
  },
  {
    "Shoes": [
      {
        "id": 1,
        "name": "Michael Kors Bag",
        "price": 235,
        "imgURL": "/imgs/03045643da82a42a4a5c86842f4b17f1.jpg"
      },
      {
        "id": 2,
        "name": "Ted Baker Bag",
        "price": 495,
        "imgURL": "/imgs/4c176b2fa86bdcddf74822c2501bbcac.jpg"
      },
      {
        "id": 3,
        "name": "Coach Bag",
        "price": 238,
        "imgURL": "/imgs/coach-jes-crossbody-signature-canvas-brown-black-59181.jpg"
      },
      {
        "id": 4,
        "name": "Kate Spade Bag",
        "price": 35,
        "imgURL": "/imgs/10.jpg"
      }
    ]
  }
]


// Get the values for merch types
const categories = storeItems.map((entry) => Object.keys(entry)[0])
console.log(categories)

// Find the products for a given merch
const merch = 'Shoes'
const products = storeItems.find((entry) => entry[merch])[merch]
console.log(products)

2 Comments

Answers without any explanation are not very useful.
Please before the code make some explanations, also you can destructurize or use flatMap on first string of code after the data

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.