1

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 someone@test.com 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("someone@test.com").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
  • 21,894
  • 86
  • 261
  • 463

1 Answers1

1

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);
});
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • 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. – PeakGen Nov 19 '20 at 15:44
  • 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. – Frank van Puffelen Nov 19 '20 at 15:46
  • 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. – PeakGen Nov 19 '20 at 15:55
  • 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. – Frank van Puffelen Nov 19 '20 at 16:10
  • Perfect. Thank you. – PeakGen Nov 19 '20 at 16:22