How to search by array-like data in Firebase Realtime Database?
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);
});
Comments
-
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 calledchat_room
where it will save all chat rooms. Eachchat_room
will hold information about its members, the people who are in the chat. Below is my data structure nowMy is requirement is, when I search by the email, I should be able to get all
chat_room
s associated to that email. For an example, i need to know allchat_room
s 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 usingSET
is a better alternative toArray
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 orArray
orHashMap
or whatever it is, my requirement is to search thechat_room
s by email.- 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 mycreateChatRoom
method above and show me how to passSET
instead ofArray
. - How can I perform the search?
- 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)
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; }
Still now sure whether this is the right one, because I am now shifting into a different node.
- If
-
PeakGen over 3 yearsThank 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 over 3 yearsOops. 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 over 3 yearsI 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
calleduser_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 over 3 yearsAh, 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 over 3 yearsPerfect. Thank you.