Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Firebase - get elements by list of IDs

I'm using firebase as my database-backend and have a many to many relationship. As my relationship is a little bit more abstract I'll go with a simplified example here. Let's say we have students and lectures. Students can attend lectures and lectures have a list of attending students. Throughout the application, both queries are needed, so that there is no real advantage of keeping the list in either one of them. This issue seems not uncommon in No-SQL scenarios like this and I've even read about storing a list of all lectures for each student and a list of students for each lecture, being a valid solution. So lets say my JSON data looks like this:

"students": {
    "s1" : {
        "name": "A",
        "lectures": ["l1", "l2"]
    },
    "s2" : {
        "name": "B",
        "lectures": ["l2", "l3"]
    }

}

and

"lectures": {
    "l1" : {
        "title": "lecture1",
        "students": ["s1"]
    },
    "l2" : {
        "title": "lecture2",
        "students": ["s1", "s2"]
    },
    "l3" : {
        "title": "lecture3",
        "students": ["s2"]
    }
}

With s1, s2, l1, l2, l3 being the cryptic Firebase IDs. Using a setup like this, it is easy to write a query in order to get all lectures of student "s1" as an array ["l1", "l2"].

However, I can't figure out how to get the corresponding lecture elements using this set of IDs, as I can only query for one ID. I also want to avoid fetching all data and filtering it afterwards using Java-Code.

like image 796
Roper Avatar asked Mar 12 '16 21:03

Roper


1 Answers

This would do the trick:

Firebase ref = new Firebase("https://stackoverflow.firebaseio.com/35963762");
ref.child("students/s1/lectures").addListenerForSingleValueEvent(new ValueEventListener() {
    public void onDataChange(DataSnapshot snapshot) {
        for (DataSnapshot lessonKey: snapshot.getChildren()) {
            ref.child("lectures").child(lessonKey.getValue(String.class)).addListenerForSingleValueEvent(new ValueEventListener() {
                public void onDataChange(DataSnapshot lectureSnapshot) {
                    System.out.println(lectureSnapshot.child("title").getValue());
                }
                public void onCancelled(FirebaseError firebaseError) {
                }
            });
        }
    }
    public void onCancelled(FirebaseError firebaseError) {
    }
});

Output:

lecture1

lecture2

A few remarks on your data structure though:

  • You are nesting data structure that should likely not be nesting. For example this code now also load the students list of lecture1 and lecture2, which it doesn't need. If you move the "students in a lecture" and "lectures for a student" into their own top-level nodes you won't have this problem.

  • You store the "students in a lecture" in an array. This means that if you remove a lecture from the middle of the array, you will have to update all of the ones after it. The more common approach is to store the lecture id as the key and a dummy true as the value:

    students_per_lecture: {
      "l2" : {
        "s1": true, 
        "s2": true
      }
    },
    
like image 135
Frank van Puffelen Avatar answered Oct 20 '22 03:10

Frank van Puffelen