Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Joining flattened data from Firebase Realtime Database using RxJava

Joining flattened data is a common use case also described in the documentation. But the documentation shows a simple example which is not real-time, it doesn't react to changes. I'm looking for a more robust implementation. I think RxJava is ideal for this.

Consider following Firebase structure:

{
  "messages": {
    "group_id_1": {
      "message_id_1": {
        "text": "Hello",
        "author": "uid_1"
      }
    }
  },
  "users": {
    "uid_1": {
      "name": "David"
    }
  },
  "rooms": {
    "room_id_1": {
      "name": "General",
      "members": {
        "uid_1": true
      }
    }
  }
}

I see two use-cases here:

  1. Get list of messages in a group with author names
    • I imagine I would get Observable<Message> and when I subscribe to it, dependencies (users for those messages) will be subscribed as well in some cache. When I'm showing the messages, I can get author's names from the cache.
    • It's also real-time - if author name changes, the observable emits changed Message.
    • When I unsubscribe to the observable, also dependencies unsubscribes.
  2. Get a list of room members with their names
    • I imagine I would get Observable<User> and when I subscribe to it, it will first subscribe to room's members and then to individual users.
    • It's real-time - if room members change, I get notified about that.
    • When I unsubscribe to the observable, also dependency unsubscribes.

Do you know about library/solution which could do that?

Or would you use it if I created one?

like image 519
David Vávra Avatar asked Oct 31 '22 00:10

David Vávra


1 Answers

I was going to pose a variation of this question but seemed like it might be better to build on top of this one...I'll describe what is hopefully at least partially the answer to above question but also then a shortcoming I'm seeing.

Using above data model we might have something like following to create RxJava wrapper around firebase query to get list of member keys for particular room and for getting details for particular member (note use of onCompleted() in subscriber.getMemberInfo...more on that later!).

public Observable<String> getRoomMembers(String roomId) {
    return Observable.create(subscriber -> {
        databaseReference.child(roomId + "/members").addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(DataSnapshot dataSnapshot) {
                for (DataSnapshot childSnapshot: dataSnapshot.getChildren()) {
                    String userId = childSnapshot.getKey()
                    subscriber.onNext(userId);
                }
                subscriber.onCompleted();
            }

            @Override
            public void onCancelled(DatabaseError databaseError) {
            }
        });
    });
}

public Observable<Member> getMemberInfo(String memberId) {
    return Observable.create(subscriber -> {
        databaseReference.child(memberId).addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(DataSnapshot dataSnapshot) {
                Member member = dataSnapshot.getValue(Member.class);
                subscriber.onNext(member);
                subscriber.onCompleted();
            }

            @Override
            public void onCancelled(DatabaseError databaseError) {
            }
        });
    });
}

What we can then do use something like following to get list of Members for particular room (have added isActive property to Member to show how we also filter results we get).

    getRoomMembers(roomId)
            .flatMap(memberId -> getMemberInfo(memberId))
            .filter(Member::isActive)
            .toList()
            .subscribe(members -> {

            });

So, the above works up to a point. The issue is that I had to call subscriber.onCompleted() in getMemberInfo for the above call to flatMap to work....which then means that any subsequent changes to Member data isn't triggering update in the above subscription. Am relatively new to RxJava and Firebase so might be missing something obvious.

like image 129
John O'Reilly Avatar answered Nov 09 '22 13:11

John O'Reilly