3

I am trying to get the filter result out from the json where the matched is true.

{
        "cat": [
            {
                "volume": "one",
                "category": [
                    {
                        "name": "Alpha",
                        "matched": true
                    },
                    {
                        "name": "Gamma",
                        "matched": false
                    }
                ]
            },
            {
                "volume": "two",
                "category": [
                    {
                        "name": "Beta",
                        "matched": false
                    },
                    {
                        "name": "Treta",
                        "matched": true
                    },
                    {
                        "name": "Neutral",
                        "matched": false
                    }
                ]
            },
            {
                "volume": "three",
                "category": [
                    {
                        "name": "Retro",
                        "matched": false
                    },
                    {
                        "name": "Jazz",
                        "matched": true
                    },
                    {
                        "name": "Rock",
                        "matched": false
                    },
                    {
                        "name": "Soft",
                        "matched": false
                    }
                ]
            }
        ]
}

Used Javascript filter

var jsonwant = jsonusing.cat.filter(function(e){
    return e.category.filter(function(e1){
        return e1.matched === true;
});
});

Js Fiddle for same

http://jsfiddle.net/xjdfaey3/

Result Should Come as

"cat": [
                {
                    "volume": "one",
                    "category": [
                        {
                            "name": "Alpha",
                            "matched": true
                        }
                    ]
                },
                {
                    "volume": "two",
                    "category": [
                        {
                            "name": "Treta",
                            "matched": true
                        }
                    ]
                },
                {
                    "volume": "three",
                    "category": [
                        {
                            "name": "Jazz",
                            "matched": true
                        }
                    ]
                }
            ]

but it is returning entire object.

5
  • You need to add an intermediate step in your double filter. e.category.filter(function(e1){ return e1.matched === true; }); does what you want, but because that is being returned to the other filter it is keeping the entire object. Commented Sep 7, 2015 at 15:13
  • Do you want to modify original object or you want to have both after filtering? Commented Sep 7, 2015 at 15:13
  • Would you want it to return those volumes for which no categories had a match? Commented Sep 7, 2015 at 15:29
  • Yes Where the match is true i want to return those volumes @ScottSauyet Commented Sep 7, 2015 at 15:40
  • But if the volume had no categories with a match, should that volume even be included in the output, e.g. {volume: "four", categories: []}? Or should that volume be excluded from the output? Commented Sep 7, 2015 at 15:56

2 Answers 2

4

I like the answer from @dsfq. It is probably as good as you will get using simple Javascript without a library. But I work on a JS functional programming library, Ramda, and that offers tools to make problems like this more tractable. Here is a one-line function to do this using Ramda:

evolve({'cat': map(evolve({category: filter(whereEq({'matched': true}))}))});

Explanation

whereEq accepts a template object and returns a predicate function that will take another object and check whether this new object has the same values for the keys of the template object. We pass it {'matched': true} so it accepts an object and checks whether this object has a 'matched' property with the value true. (This is oversimplified a bit. The function, like most Ramda functions actually is automatically curried, and would accept the test object initially, but since we don't supply one, it simply returns a new function that is expecting it. All the functions below act the same way, and I won't mention it for each.)

The function generated by whereEq is passed to filter. Filter accepts a predicate function (one which tests its input and returns true or false) and returns a function which accepts a list of objects, returning a new lists consisting of only those ones for which the function returned true.

Using this, we create an object to pass to evolve. This function accepts a configuration object that maps property objects to transformation functions. It returns a new function that accepts an object and returns a copy of it, except where transformation functions have been declared in the configuration object. There it returns the result of running that transformation against the data from the object. In our case, it will run the filter we've just built against the category property.

The function generated here is passed to map, which takes a function and returns a new function that accepts a list and returns the result of applying that function to every element of the list. Here that will end up being the collection of volumes.

Now the result of this map call is passed to evolve again for the property 'cat' of the outermost object. This is the final function. You can see it in action in the Ramda REPL.


I'm not trying to claim that this is inherently better. But tools that help you look at problems from a higher level of abstraction often let you write more succinct code.

Sign up to request clarification or add additional context in comments.

Comments

3

You also need to modify internal category array after filtering:

var jsonwant = jsonusing.cat.filter(function(e){
    return (e.category = e.category.filter(function(e1){
        return e1.matched === true;
    })).length;
});

Note, that this will modify original object too.

UPD. In order to preserve original structure one more mapping step is needed to create new array:

var jsonwant = jsonusing.cat.map(function(e) {
    return {
        volume: e.volume,
        category: e.category.filter(function(e1){
            return e1.matched === true;
        })
    };
})
.filter(function(e) {
    return e.category.length;
});

2 Comments

It is working perfectly. I am little bit new to javascript. Can you please explain how the internal JSON is getting filtered. This will help a lot.
For every object in cat array you also want to update inner e.category array, because it also has to be filtered. So you overwrite e.category with filtered version. Then you need to return true/false (or 1/0 - are also will get converted to true/false in filter) in order to filter items of outer cat array.

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.