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

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.