Search code examples
javaandroidfirebasefirebase-realtime-databasedatabase-trigger

How can I query in firebase android like database trigger in cloud function


In Firebase Cloud Functions (Javascript), we use database trigger like below,

functions.database.ref('/DoctorApp/DrTimeSlot/{doctorUID}/Patients/{patientID}')
    .onCreate((snapshot, context) => { 

    // codes here
};

Here, {doctorUID} is not known so all function is working on all UIDs.

Is this possible to use the same method in Android Studio (Java)? below this code is not working for me, can you provide me the alternate of the code.

Query query = rootData.child("DrTimeSlot/{drUID}/Patients/").orderByChild("patientUID").equalTo(auth.getUid());

query.addValueEventListener(new ValueEventListener() {
            @Override
            public void onDataChange(@NonNull DataSnapshot dataSnapshot) {

                //codes here
            }

            @Override
            public void onCancelled(@NonNull DatabaseError databaseError) {

            }
        });

Solution

  • While not possible to use the same syntax as Cloud Functions, your query to find all doctors with a given patient ID can be achieved using:

    Query query = rootData.child("DrTimeSlot").orderByChild("Patients/" + auth.getUid()).startAt(""); // startAt("") will exclude non-existent values
    
    query.addValueEventListener(new ValueEventListener() {
        @Override
        public void onDataChange(@NonNull DataSnapshot queryDataSnapshot) {
            if (queryDataSnapshot.hasChildren()) {
                // handle no results
                System.out.println("No results returned");
                return;
            }
    
            for (DataSnapshot doctorDataSnapshot: dataSnapshot.getChildren()) {
                // TODO: handle the data
                System.out.println(doctorDataSnapshot.getKey() + " => " + doctorDataSnapshot.getValue());
            }
        }
    
        @Override
        public void onCancelled(@NonNull DatabaseError databaseError) {
            // Getting doctors failed, log a message
            Log.w(TAG, "findDoctorsForUser:onCancelled", databaseError.toException());
        }
    });
    

    However, to permit such an operation, the client must have read access to every single doctor's data, even if the user performing the search is not a patient of that doctor. It will also be entirely processed on the client device which means downloading all of the data under "DrTimeSlot" which is not recommended and is also a massive security & privacy risk.

    Instead, in the user data of a particular user, store a list of their doctors. When you need to find them, download /users/userId1/doctors and then get the needed patient data from each doctor restricting read/write access to that doctor and that user only.

    "users": {
      "userId1": {
        "doctors": {
          "doctorId1": true, // boolean value for simplicity
          "doctorId2": "paediatrician", // could also use value for type
          "doctorId3": 10, // or number of visits
          "doctorId4": false, // or if they are an active patient of this doctor
        },
        ...
      },
      ...
    }