I had the exact similar problem retrieving users by IDs. I found that there was no way of making the IN
query in Firebase
.
David suggests in his video either denormalizing the database or making a query for every id.
I did not like denormalizing so I queried every user.
If you're in to RxJava, here's what I did
@NonNull
private Observable<List<User>> userIdsToUsers(@NonNull final List<String> uids) {
if (uids.isEmpty()) {
return Observable.just(new ArrayList<>());
}
return Observable.combineLatest(userIdsToUserObservables(uids),
new ListCastFunc<>(User.class));
}
@NonNull
private List<Observable<User>> userIdsToUserObservables(@NonNull final List<String> uids) {
final List<Observable<User>> result = new ArrayList<>();
for (final String uid : uids) {
result.add(userIdToUserObservable(uid));
}
return result;
}
@NonNull
private Observable<User> userIdToUserObservable(@NonNull final String uid) {
return RxFirebaseDatabase.observeValueEvent(getUsersReference().orderByKey().equalTo(uid))
.flatMap(this::dataSnapshotToUserObservable);
}
@NonNull
private Observable<User> dataSnapshotToUserObservable(@NonNull final DataSnapshot ds) {
return Observable.fromCallable(() -> dataSnapshotToUser(ds));
}
@Nullable
private static User dataSnapshotToUser(@NonNull DataSnapshot ds) {
if (!ds.exists()) {
return null;
}
return parsedObjHere;
}
private static final class ListCastFunc<T> implements FuncN<List<T>> {
@NonNull
private final Class<T> targetClass;
ListCastFunc(@NonNull final Class<T> targetClass) {
this.targetClass = targetClass;
}
@Override
public List<T> call(final Object... args) {
if (args == null || args.length == 0) {
return new ArrayList<>();
}
final List<T> results = new ArrayList<>(args.length);
for (final Object arg : args) {
if (arg != null && targetClass.isAssignableFrom(arg.getClass())) {
//noinspection unchecked
results.add((T) arg);
}
}
return results;
}
}