karagkalex
karagkalex

Reputation: 95

Filtering a nested object based on 2 values

so I want to create a filter that returns data based upon the link, if the link contains /rome/ it will list all the pages that contains /rome/ which I've managed to do. But I'm also trying to create a filter based on the market within the cities, for example if the link contains /rome/supermarket/ I want to filter out the pages to return only the pages that contain the city and the market meaning id 1 and 2 in my last link example.

First I'm thinking that I need to loop all over the pages, which are 3 in my example and then loop over again for each city to check if it contains that city and the supermarket and based upon that return the filtered data. I've tried a couple of things but I'm scratching my head here.

 pages: [
    {
      id: 1,
      name: 'Meals',
      startDate: '2022-11-09 10:32:00',
      endDate: '2022-11-16 10:32:00',
      cities: {
        rome: ['supermarket'],
      },
    },
    {
      id: 2,
      name: 'Deals',
      startDate: '2022-11-24 11:01:00',
      endDate: '2022-12-01 11:01:00',
      cities: {
        napoli: ['supermarket', 'minimarket'],
        rome: ['supermarket'],
      },
    },
    {
      id: 3,
      name: 'Toys',
      startDate: '2022-11-24 11:01:00',
      endDate: '2022-12-01 11:01:00',
      cities: {
        rome: ['minimarket'],
        venice: ['supermarket', 'minimarket'],
      },
    }
]

The filter for the city ->

      const pagesFilterCity = pages.filter((item) => {
        return item.cities.hasOwnProperty(city); // where city is 'rome'
      });

What I've tried ->

      const pagesFilterMarket = pages.filter((item) => {
        return Object.values(item.cities)
          .flat()
          .some((item) => item === market); // where market is 'supermarket'
      });

But this will only loop through the first instance from each cities, meaning 3 times

Wanted result: after having /rome/supermarket in the link I want to create a filter that should return the following data from the pages example from above -> Note that extracting the data from the link I've already done and that's not my question

 pages: [
    {
      id: 1,
      name: 'Meals',
      startDate: '2022-11-09 10:32:00',
      endDate: '2022-11-16 10:32:00',
      cities: {
        rome: ['supermarket'],
      },
    },
    {
      id: 2,
      name: 'Deals',
      startDate: '2022-11-24 11:01:00',
      endDate: '2022-12-01 11:01:00',
      cities: {
        napoli: ['supermarket', 'minimarket'],
        rome: ['supermarket'],
      },
    }
] // wanted result

Upvotes: 0

Views: 49

Answers (3)

Yosvel Quintero
Yosvel Quintero

Reputation: 19070

You can use Array.prototype.filter() combined with Optional chaining (?.) and Array.prototype.includes():

Code:

const pages = [{id: 1,name: 'Meals',startDate: '2022-11-09 10:32:00',endDate: '2022-11-16 10:32:00',cities: {rome: ['supermarket'],},},{id: 2,name: 'Deals',startDate: '2022-11-24 11:01:00',endDate: '2022-12-01 11:01:00',cities: {napoli: ['supermarket', 'minimarket'],rome: ['supermarket'],},},{id: 3,name: 'Toys',startDate: '2022-11-24 11:01:00',endDate: '2022-12-01 11:01:00',cities: {rome: ['minimarket'],venice: ['supermarket', 'minimarket']}}]

const result = pages.filter(o => o.cities['rome']?.includes('supermarket'))

console.log(result)

Upvotes: 0

Svetoslav Petrov
Svetoslav Petrov

Reputation: 1198

From what I understand you are checking two things:

  1. Does the cities object contains the needed city
  2. Does the city has the specific market

This can be achieved with something similar to:

const pages = [{
    id: 1,
    name: 'Meals',
    startDate: '2022-11-09 10:32:00',
    endDate: '2022-11-16 10:32:00',
    cities: {
        rome: ['supermarket'],
    },
},
{
    id: 2,
    name: 'Deals',
    startDate: '2022-11-24 11:01:00',
    endDate: '2022-12-01 11:01:00',
    cities: {
        napoli: ['supermarket', 'minimarket'],
        rome: ['supermarket'],
    },
},
{
    id: 3,
    name: 'Toys',
    startDate: '2022-11-24 11:01:00',
    endDate: '2022-12-01 11:01:00',
    cities: {
        rome: ['minimarket'],
        venice: ['supermarket', 'minimarket'],
    },
},
];

const search = (location, market) => {
    return pages.filter((record) => 
        // Check if the cities property has a value
        record.cities[location] && 
        // Check if the specific city has the given market
        record.cities[location].some((type) => type === market)
    );
};

console.log(search('rome', 'supermarket'));

If you want to do an extra check and be on the safe side you can include also

return pages.filter((record) => 
    record.cities[location] && 
    record.cities[location].length &&
    record.cities[location].some((type) => type === market)
);

Upvotes: 1

Salketer
Salketer

Reputation: 15711

You can split the string in two using the / to have city and service. Then you simply check if service is empty OR if the city array contains the service requested.

const pages = [{
    id: 1,
    name: 'Meals',
    startDate: '2022-11-09 10:32:00',
    endDate: '2022-11-16 10:32:00',
    cities: {
      rome: ['supermarket'],
    },
  },
  {
    id: 2,
    name: 'Deals',
    startDate: '2022-11-24 11:01:00',
    endDate: '2022-12-01 11:01:00',
    cities: {
      napoli: ['supermarket', 'minimarket'],
      rome: ['supermarket'],
    },
  },
  {
    id: 3,
    name: 'Toys',
    startDate: '2022-11-24 11:01:00',
    endDate: '2022-12-01 11:01:00',
    cities: {
      rome: ['minimarket'],
      venice: ['supermarket', 'minimarket'],
    },
  }
]

function filter(search) {
  const [city, service] = search.split('/');
  return pagesFilterCity = pages.filter((item) => {
    return item.cities.hasOwnProperty(city) && (service === '' || item.cities[city].includes(service)); // where city is rome for example
  });
}
console.log(filter('rome/supermarket'))

Upvotes: 0

Related Questions