0

I want to filter some information using the javascript filter functionality but i can't seem to get it to work. Given i have some raw data as below:

{
    "salesWeeks": [
        {
            "date": "29/03/2019",
            "locations": [
                {
                    "name": "London",
                    "totalUnits": 15,
                    "cars": [
                        {
                            "name" : "Audi",
                            "units": 5
                        },
                        {
                            "name": "BMW",
                            "units": 10
                        }
                    ]
                }
            ] 
        },
        {
            "date": "29/03/2019",
            "locations": [
                {
                    "name": "Paris",
                    "totalUnits": 22,
                    "cars": [
                        {
                            "name" : "Audi",
                            "units": 2
                        },
                        {
                            "name": "BMW",
                            "units": 10
                        },                    
                        {
                            "name": "Porsche",
                            "units": 10
                        }
                    ]
                }
            ] 
        }
    ]
}

I want to filter this data in my UI by the name of the car. If a user selects a filter option which returns an array with ['Audi'].

What would i need to do in order to get the following response:

{
    "salesWeeks": [
        {
            "date": "29/03/2019",
            "locations": [
                {
                    "name": "London",
                    "totalUnits": 15,
                    "cars": [
                        {
                            "name" : "Audi",
                            "units": 5
                        }
                    ]
                }
            ] 
        },
        {
            "date": "29/03/2019",
            "locations": [
                {
                    "name": "Paris",
                    "totalUnits": 22,
                    "cars": [
                        {
                            "name" : "Audi",
                            "units": 2
                        }
                    ]
                }
            ] 
        }
    ]
}

My best guess approach has been:

https://jsfiddle.net/hwt3k2sn/7/

var salesWeeks = [{"date":"29/03/2019","locations":[{"name":"London","totalUnits":15,"cars":[{"name":"Audi","units":5},{"name":"BMW","units":10}]}]},{"date":"29/03/2019","locations":[{"name":"Paris","totalUnits":22,"cars":[{"name":"Audi","units":2},{"name":"BMW","units":10},{"name":"Porsche","units":10}]}]}]

salesWeeks = salesWeeks
.filter(week => {
    return week.locations
    .some(location => {
        return location
        .cars.filter(cars => { cars.name == "Audi" })
    })
})

console.log(salesWeeks)

it just seems to ignore the filter at the end though :\ if anyone has a fix for this i would really appreciate the help, it's probably fairly simple for someone well versed in the ways of the Javascript.

1
  • 1
    You're close, your filter at the end tho always returns true, because it returns an array - check the arrays length: return location .cars.filter(cars => { cars.name == "Audi" }).length Commented Mar 5, 2019 at 16:05

3 Answers 3

2

When your expect response does not the same type with origin raw data, you have need more operators.

In your case I use .map function to do it:

var salesWeeks = [{"date":"29/03/2019","locations":[{"name":"London","totalUnits":15,"cars":[{"name":"Audi","units":5},{"name":"BMW","units":10}]}]},{"date":"29/03/2019","locations":[{"name":"Paris","totalUnits":22,"cars":[{"name":"Audi","units":2},{"name":"BMW","units":10},{"name":"Porsche","units":10}]}]}]

const CAR_BRANDS = ["Audi", "Porsche"];

salesWeeks = salesWeeks
.filter(week => {
    return week.locations
    .some(location => {
        return !!location
        .cars.filter(car => CAR_BRANDS.includes(car.name)).length // return a bolean value length = 0 => false...
    })
})
.map(week => {
  week.locations = week.locations.map(l => {
    l.cars = l.cars.filter(car => CAR_BRANDS.includes(car.name)); // only keep a car
    return l;
  });
  return week;
});

console.log(JSON.stringify(salesWeeks, null, 4));
Sign up to request clarification or add additional context in comments.

Comments

0

Try this. Few .some() might help.

const obj = {
    "salesWeeks": [
        {
            "date": "29/03/2019",
            "locations": [
                {
                    "name": "London",
                    "totalUnits": 15,
                    "cars": [
                        {
                            "name" : "Audi",
                            "units": 5
                        }
                    ]
                }
            ] 
        },
        {
            "date": "29/03/2019",
            "locations": [
                {
                    "name": "Paris",
                    "totalUnits": 22,
                    "cars": [
                        {
                            "name" : "Toyota",
                            "units": 2
                        },
                        {
                            "name" : "Mercedes",
                            "units": 5
                        }
                    ]
                }
            ] 
        }
    ]
}

const filterByCar = (arr, carBrand) => {
  return arr.filter(week => week.locations.some(loc => loc.cars.some(car => car.name === carBrand)))
}

console.log(filterByCar(obj.salesWeeks, 'Toyota'))

3 Comments

What about multiple brands in the same cars array? This won't filter them out
@jo_va added Mercedes to the Paris location, take a look, it won't filter them out.
sorry I edited my comment, I meant it won't filter them out, which it does not, the OP wants to only keep the cars matching the given name
0

You can do it using Array.reduce():

  1. Iterate over your weeks with reduce and an initial empty array.
  2. For each week, map the locations to a new array whose cars entries are filtered to remove the unwanted cars.
  3. If there are any locations, and if there are any cars left for those locations, push a new week to the output array by copying the week and overriding its locations with the new one.

const salesWeeks = [{"date":"29/03/2019","locations":[{"name":"London","totalUnits":15,"cars":[{"name":"Audi","units":5},{"name":"BMW","units":10}]}]},{"date":"29/03/2019","locations":[{"name":"Paris","totalUnits":22,"cars":[{"name":"Audi","units":2},{"name":"BMW","units":10},{"name":"Porsche","units":10}]}]}]

const filterByCar = (data, car) => data.reduce((acc, week) => {
  const locations = week.locations.map(l => ({ ...l, cars: l.cars.filter(c => c.name === car) }));
  if (locations.length && locations.some(l => l.cars && l.cars.length)) {
    acc.push({ ...week, locations });
  }
  return acc;
}, []);

console.log(filterByCar(salesWeeks, 'Audi'));
console.log(filterByCar(salesWeeks, 'Porsche'));
console.log(filterByCar(salesWeeks, 'Whatever'));

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.