I have an array of users
and I want to grab a subset of them based on an inexpensive lookup in a redis set.
const users = [
{ _id: '1', name: 'george', age: 36 },
{ _id: '2', name: 'henry', age: 33 },
{ _id: '3', name: 'agatha', age: 28 },
{ _id: '4', name: 'janet', age: 29 },
{ _id: '5', name: 'gary', age: 21 },
// ... 995 more users
]
const db = {/* my redis connection */}
const isInside = (db, user) => {
return db.contains('my:set:key', user._id)
}
I have tried Array.prototype.filter
but it doesn’t seem to work
users.filter(user => isInside(db, user))
// => always gives me back all the users even when I see they are not in the set
I know something is wrong here. How do I filter out users using isInside
?
2
Answers
The problem is that
filter
is always synchronous and your DB calls are asynchronous, filter function always returnstrue
because itsdb.contains
is a running promise, so it converts totrue
.One of the solutions could be, to create an array of promises, wait for all of them, and then filter out.
You will probably be OK with
Promise.all(users.map(user => isInside(db, user)))
but there’s a danger of hitting the database too hard with multiple simultaneous requests, particularly with some 3rd-party cloud services.If so, then you can orchestrate an asynchronous filter in which db queries are performed sequentially, based on Array.prototype.reduce.
It’s a bit of a palaver, but not too bad:
Of course, this will be slower than a
.map()
solution but if.map()
doesn’t work ….