Nataly Firstova
Nataly Firstova

Reputation: 821

Ramda filter data with gte condition

I have JSON with data

 {
   "date": "2019-12-17",
   "installs": 1,
 },
 {
   "date": "2019-12-02",
   "installs": 5
 },
 {
   "date": "2019-12-02",
   "installs": 4
 }
 ....

and i need to filter this by gte condition on one field (installs, for example)

i tried with this code:

    let f = R.filter(R.propIs(true, R.gte(R.prop('installs'), 2)), data);
    console.log(f)

but got error

TypeError: Right-hand side of 'instanceof' is not an object

Upvotes: 0

Views: 406

Answers (1)

Scott Sauyet
Scott Sauyet

Reputation: 50807

I think your attempt shows some confusion about how to use Ramda's ideas on functional composition. Probably the working version closest to yours would look like this:

filter(pipe (prop ('installs'), gte (__, 2), equals (true)), data)

I will pull out and name the function passed to filter for our discussion. If you have no other use for it, of course it can be inlined again later.

const enoughInstalls = pipe (prop ('installs'), gte (__, 2), equals (true))
filter (enoughInstalls) (data)

Note that when we want to create a function that passes data from one function to another, we don't nest them with something like gte(prop('installs'), 2). Because prop('installs') is a function, this would entail passing a function as the first argument to gte. Of course you need to pass a number instead. When we want to pass the results of one function call to another, we use functional composition, usually using Ramda's compose or its pipe. We'll do the latter here, but compose is quite similar, simply with the arguments reversed.

So instead of gte(prop('installs'), 2) we use pipe(prop('installs'), gte(__, 2)). This returns a function which passes its argument(s) to prop('installs') and passes the result of that call to gte(__, 2). Above there is one more call in the pipeline, equals(true). That's trying to match your propIs idea. But it turns out to be entirely unnecessary. gte will return a boolean. So adding equals(true) to that simply returns the same boolean. So this can be simplified to:

const enoughInstalls = pipe (prop ('installs'), gte (__, 2))

This now says to grab the property installs from our input object and pass it to the predicate function gte(__, 2). But there is a built-in function for that, propSatisfies. We could rewrite this to:

const enoughInstalls = propSatisfies (gte (__, 2), 'installs')

This is a perfectly reasonable solution. But I actually prefer the version Nick Parsons suggested in the comments. For this one, I really prefer to inline in the filter call:

const myFilter = filter (where ({installs: gte(__, 2)})

Reading that aloud as "filter where installs is greater than or equal to 2" makes this almost as readable as can be imagined.

Upvotes: 2

Related Questions