How to search by array-like data in Firebase Realtime Database?

114

Yes, the approach I give in the linked answer is that way to allow searching for chatrooms for a specific user. You'll end up with a secondary data structure that maps users to their associated chat rooms.

To save this additional data structure, you loop over the children, writing essentially the inverse of what you already have. Something like:

var newChatRoomRef = _chatRoomReference.push();
var newChatRoomKey = newChatRoomRef.key;
await newChatRoomRef.set({
  'last_message': lastMessage,
  'chat_mode': chatMode,
  'members': [members[0].email, members[1].email],
  'timestamp': DateTime.now().millisecondsSinceEpoch,  
});
var userChatRoomsRef = FirebaseDatabase.instance.reference().child('user_chatrooms')
members.forEach((member) {
  userChatRoomsRef.child(member.uid).child(newChatRoomKey).set(true);
});
Share:
114
PeakGen
Author by

PeakGen

CTO

Updated on December 25, 2022

Comments

  • PeakGen
    PeakGen over 1 year

    I am developing a flutter app with Firebase Realtime Database facility. This is kind of a chat app. Here i have a root node called chat_room where it will save all chat rooms. Each chat_room will hold information about its members, the people who are in the chat. Below is my data structure now

    enter image description here

    My is requirement is, when I search by the email, I should be able to get all chat_rooms associated to that email. For an example, i need to know all chat_rooms where the email ID [email protected] is registered with.

    The issue is, i am now aware that I can't do that with my current structure, where I save data as an array. Reading this i got to know that using SET is a better alternative to Array as it we are allowed to perform such searches. So maybe this is the structure I need.

     chat_room
          chatroom1
            chat_mode: "supplier",
            last_message: "test",
            timestamp: 1223334
            members:
                email1: true
                email2: true
          chatroom2
            chat_mode: "supplier",
            last_message: "test",
            timestamp: 1223334
            members:
                email1: true
                email2: true
    

    Below is the code I am using to search by email and it gives me NOTHING.

    final DatabaseReference reference = FirebaseDatabase.instance.reference().child('chat_room');
    reference.orderByChild("members").equalTo("[email protected]").once();
    

    Currently, this is how I save data to chat_room.

    //Create chat_room
      Future<String> createChatRoom({String lastMessage, String chatMode, List<ChatMember> members}) async {
        
        var newChatRoomRef = _chatRoomReference.push();
        var newChatRoomKey = newChatRoomRef.key;
        await newChatRoomRef.set({
          'last_message': lastMessage,
          'chat_mode': chatMode,
          'members': [members[0].email, members[1].email],
          'timestamp': DateTime.now().millisecondsSinceEpoch,
          
        });
    
        return newChatRoomKey;
      }
    

    Whether it is SET data structure or Array or HashMap or whatever it is, my requirement is to search the chat_rooms by email.

    1. If SET data structure is the answer to this, how can I save it to firebase? How do I prepare my data so i can send it properly? Please feel free to take my createChatRoom method above and show me how to pass SET instead of Array.
    2. How can I perform the search?
    3. If set is not the answer, then what is it?

    Appreciate your support.

    EDIT

    According to @Frank suggestion, I made my code like this, copying the exact code he provided.

    //Create chat_room
      Future<String> createChatRoom(
          {String lastMessage, String chatMode, List<ChatMember> members}) async {
        var newChatRoomRef = _chatRoomReference.push();
        var newChatRoomKey = newChatRoomRef.key;
        await newChatRoomRef.set({
          'last_message': lastMessage,
          'chat_mode': chatMode,
          'members': [members[0].email, members[1].email],
          'timestamp': DateTime.now().millisecondsSinceEpoch,
        });
        var userChatRoomsRef =
            FirebaseDatabase.instance.reference().child('chat_room');
        members.forEach((member) {
          userChatRoomsRef
              .child(member.userID.toString() + "-userID")
              .child(newChatRoomKey)
              .set(true);
        });
    
        return newChatRoomKey;
      }
    

    The, this is the structure it generated. (Please note that 30-userID and 50-userID are actual User IDs as I am not using UID from Firebase Auth)

    enter image description here

    Anyway I am really not sure whether this is the correct structure I should have.

    EDIT 2

    According to @Frank edit, this is how i MADE my code and database structure it generated.

    //Create chat_room
      Future<String> createChatRoom(
          {String lastMessage, String chatMode, List<ChatMember> members}) async {
        var newChatRoomRef = _chatRoomReference.push();
        var newChatRoomKey = newChatRoomRef.key;
        await newChatRoomRef.set({
          'last_message': lastMessage,
          'chat_mode': chatMode,
          'members': [members[0].email, members[1].email],
          'timestamp': DateTime.now().millisecondsSinceEpoch,
        });
        var userChatRoomsRef =
            FirebaseDatabase.instance.reference().child('user_chatrooms');
        members.forEach((member) {
          userChatRoomsRef
              .child(member.userID.toString() + "-userID")
              .child(newChatRoomKey)
              .set(true);
        });
    
        return newChatRoomKey;
      }
    

    enter image description here

    Still now sure whether this is the right one, because I am now shifting into a different node.

  • PeakGen
    PeakGen over 3 years
    Thank you for the reply. i made changed to my code. The code and the database structure it generated are both in my edited question. I am really not sure whether that is what you wanted to generate. Please check.
  • Frank van Puffelen
    Frank van Puffelen over 3 years
    Oops. That should've been a different top-level node, as explained in my answer to the question you linked. I updated the code in my answer.
  • PeakGen
    PeakGen over 3 years
    I have made edits to my code, posted the database struture and the code in my edited answer. In there you seems to create a new node called user_chatrooms. But still i see no way of searching for chats via email. Is this is right? Or I have to search user_chat rooms by user id to find the related chat rooms? Thats also fine. please advice.
  • Frank van Puffelen
    Frank van Puffelen over 3 years
    Ah, if you want to access them by email, you'll need to use the (encoded) email as the key instead of the UID I used above. Well... or store the email as the value, instead of true as I've done in my answer.
  • PeakGen
    PeakGen over 3 years
    Perfect. Thank you.