I’m trying to create an app where I need to match two random users from my Firebase Database. The problem I have is that I‘m not sure how to connect every user of the database to random pairs:
As far as I thought the user might press a button to signal that he‘s ready, so a child of his UID like 'searching' turns from false to true. By receiving a DataSnapshot the user can see if another user is searching too. Then I thought of turning the 'searching' state to false for both users and create a new UniqueID to connect them.
But like that it‘s thought pretty short, I think and would cause some problems. Can anyone give me a hint on how to organize that searching process?
Actually using a special node like searching and setting it to true and false will be a good idea.
You can use orderByChild() to order all the users with searching node set to true and get the uid of any of those users.
To make the process random you could make a call to users, take the ids given back to you, and pick one at random with a basic random number.
If after making a call to users you have 10 user ids in an array you would want to get a random number between 0-9 and then make a call to firebase with the userId.
I don't believe Firebase has any built in code for this. So this would be the best thing you can do to achieve this feature in your app.
To give a basic idea, your database structure should look something like this:
--rootNode
|
|
-- uid1
| |
| - searching
| - other Fields
|
-- uid2
.
.
.
Related
In my web application made with Ionic and Firestore, I would like to select 5 random items to put on sale- The items are documents that are in a collection collectA . To do this I have seen that firebase does not allow to get documents in a random way, but a possible solution to get them is shown in this post Firestore: How to get random documents in a collection .
But I would like 5 random items to be taken, then another 5 that have not already been taken, and so on. When all items have been taken, you start over. Would it be a good solution to consider a new collectB collection in which to insert the 5 randomly taken items and delete them from the collectA collection? Then do it for all the items taken. When collectA becomes empty and all items are in collectB, do the same process but from collectB to collectA. The disadvantage I think is only in the increased cost of the write-offs ($0.02 per 100,000). The writes are not because when I take the 5 random items I still have to modify some fields of these documents. I don't want the queries to slow down or the costs to increase a lot.
If you need 5 new random items for all your users in the application, then don't do that operation in Firestore, do it in the Realtime Database, it's much cheaper for choosing such random items. Both databases are working really well together in the same project. That being said, you can have a structure that looks like this:
Firebase-root
|
--- products
| |
| --- $productId: true
| |
| --- $productId: true
|
--- consumedProducts
|
--- $productId: true
|
--- $productId: true
There are two solutions to this problem. Every time you get 5 new random IDs from the "products" node, add them also to the "consumedProducts" node. To be able not to choose the same IDs again, always check if the new IDs are not already present in the "consumedProducts" node. After a while, when the "consumedProducts" will contain the same IDs as the "products" node, then you can simply remove it and start over again. The second solution might be to add those 5 elements into the "consumedProducts" and right after that delete them from "products" node. When the "products" node remains empty, do the same thing with the "consumedProducts".
Now according to the logic of your app, you should decide which one is better to be used, but remember, always keep in sync, the actual products from Firestore with corresponding IDs in the Realtime Database. For instance, if you add a new product in Firestore, add the corresponding ID in the Realtime Database node. That should happen also when you delete a product from Firestore.
I am struggling to find a solution for an interesting thing I need to do in Firestore.
Would be awesome if you help me. I will try to explain:
I have something like poker tables, where users can create tables and join them. When a user has a table opened other users can see him in the table. When he leaves the table he should disappear ( here is where I have the problem )
Leaving the table can happen by navigating to other page, by closing tab, etc. He can be in the same table in different tabs, browsers or devices ( i can change this if there is no other option ).
So what I need is to display which players are connected to a table.
Can you think of an optimal solution? How would you implement this?
.
If it helps, some things I tried but don't work:
listen from server side when user closes the websocket that listen for changes in a table and, if there is no other socket opened for that user and table, remove that user from table.
=> it is not possible
create a setInterval clientSide to update a timestamp in db for the user in table every 10 seconds. Then, when displaying the table, filter players by this tiemestamp being newer than Date.now() - 15 seconds
=> it doesn´t work good, it has glitches and a lot of updates to DB
I also tried the buildPresence hack with realtime database but it doesnt help. It is just usefull for knowing that user is online, not when he leaves specific table.
So what I need is to display which players are connected to a table. Can you think of an optimal solution? How would you implement this?
The most simple solution I can think of is to create a collection of tables and store in each document an array of user ids:
Firestore-root
|
--- tables (collection)
|
--- tableId (document)
|
--- users: ["usersIdOne", "usersIdTwo", "usersIdThree"]
Now to check wich players are connected to a table, you can simply attach a realtime listener on a document/query so you can get data in realtime. This means that once a player joins or leaves a table, the listener will fire and you'll be notified instantly.
To add a user to a table, simply add its uid in the users array and to remove a listener, remove its uid from the users array. For more informations:
https://firebase.google.com/docs/firestore/manage-data/add-data
Please see arrayUnion and arrayRemove.
Following Current Datamodell
User
User ID
Video
VideoID
LikedBy (Subcol)
User ID
User ID
User ID
Now if a User visits a video I wanna show if he Liked the Video already or not (similar to youtubes button color if you liked already).
My current approach is querieing for a Document with the Key of the signed In UserID and if I find one it means the user liked the video. The problem is I have this for Artists that you can subscribe too similar to channels on youtube.
This alone created about 3x the initial Reads I have on Page Load.
I would like to hear if there is any more efficient way to query for such a thing or structure the data.
Be aware that if you suggest me to store all liked Shows in the User or Show Document that this is not scalable due to the 1MB Limit.
1) You can have a subcollection on the Users, storing the ids of the posts the likes.
2) You can create a users_likes, collections where the Ids is the user id and inside have an array with the ids of the posts the user likes.
3) Last, just make props called likes on the user collection an store the ids of the posts.
All options have a trade-off, I would make like a user and posts_likes query on load and keep that in memory (no external user is going to affect this).
Be aware that if you suggest me to store all liked Shows in the User or Show Document that this is not scalable due to the 1MB Limit.
If you are expecting a user to like more than 1 millions of posts... otherwise, storing 1Mb of only ids is a good idea... I use this same pattern for a user events tracking, I have events defined (equivalent to your posts) and the user make actions that correlate to those events (your likes), I have cases with more than 80K and it works like charm. I gave your 3 options, I would say, start with 3 until it doesnt work, then go to 2 and same process up to 1. Since you will work with array of ids, support yourself with this
My current approach is querieing for a Document with the Key of the signed In UserID and if I find one it means the user liked the video.
Yes, that's a correct approach.
This alone created about 3x the initial Reads I have on Page Load.
I don't know where this is coming from but there is certainly something wrong. Unfortunately, nothing in your question can help me see the problem.
I would like to hear if there is any more efficient way to query for such a thing or structure the data.
I don't understand much from your schema, but I would structure the database this way:
Firestore-root
|
--- users (collection)
| |
| --- uid (document)
| |
| --- //user properties
|
--- video (collection)
|
--- videoId (document)
|
--- likedBy: ["uid", "uid", "uid"]
As you can see, likedBy property is of type array. So once you get a video document, you can simply check the uid of the logged in user against the likedBy array. If it exists, it means that user has already liked that video, otherwise has not.
I've read almost everywhere about structuring one's Firebase Database for efficient querying, but I am still a little confused between two alternatives that I have.
For example, let's say I want to get all of a user's "maxBenchPressSessions" from the past 7 days or so.
I'm stuck between picking between these two structures:
In the first array, I use the user's id as an attribute to index on whether true or false. In the second, I use userId as the attribute NAME whose value would be the user's id.
Is one faster than the other, or would they be indexed a relatively same manner? I kind of new to database design, so I want to make sure that I'm following correct practices.
PROGRESS
I have come up with a solution that will both flatten my database AND allow me to add a ListenerForSingleValueEvent using orderBy ONLY once, but only when I want to check if a user has a session saved for a specific day.
I can have each maxBenchPressSession object have a key in the format of userId_dateString. However, if I want to get all the user's sessions from the last 7 days, I don't know how to do it in one query.
Any ideas?
I recommend to watch the video. It is told about the structuring of the data very well.
References to the playlist on the firebase 3
Firebase 3.0: Data Modelling
Firebase 3.0: Node Client
As I understand the principle firebase to use it effectively. Should be as small as possible to query the data and it does not matter how many requests.
But you will approach such a request. We'll have to add another field to the database "negativeDate".
This field allows you to get the last seven entries. Here's a video -
https://www.youtube.com/watch?v=nMR_JPfL4qg&feature=youtu.be&t=4m36s
.limitToLast(7) - 7 entries
.orderByChild('negativeDate') - sort by date
Example of a request:
const ref = firebase.database().ref('maxBenchPressSession');
ref.orderByChild('negativeDate').limitToLast(7).on('value', function(snap){ })
Then add the user, and it puts all of its sessions.
const ref = firebase.database().ref('maxBenchPressSession/' + userId);
ref.orderByChild('negativeDate').limitToLast(7).on('value', function(snap){ })
I'm designing a chat app much like Facebook Messenger. My two current root nodes are chats and users. A user has an associated list of chats users/user/chats, and the chats are added by autoID in the chats node chats/a151jl1j6. That node stores information such as a list of the messages, time of the last message, if someone is typing, etc.
What I'm struggling with is where to make the definition of which two users are in the chat. Originally, I put a reference to the other user as the value of the chatId key in the users/user/chats node, but I thought that was a bad idea incase I ever wanted group chats.
What seems more logical is to have a chats/chat/members node in which I define userId: true, user2id: true. My issue with this is how to efficiently query it. For example, if the user is going to create a new chat with a user, we want to check if a chat already exists between them. I'm not sure how to do the query of "Find chat where members contains currentUserId and friendUserId" or if this is an efficient denormalized way of doing things.
Any hints?
Although the idea of having ids in the format id1---||---id2 definitely gets the job done, it may not scale if you expect to have large groups and you have to account for id2---||---id1 comparisons which also gets more complicated when you have more people in a conversation. You should go with that if you don't need to worry about large groups.
I'd actually go with using the autoId chats/a151jl1j6 since you get it for free. The recommended way to structure the data is to make the autoId the key in the other nodes with related child objects. So chats/a151jl1j6 would contain the conversation metadata, members/a151jl1j6 would contain the members in that conversation, messages/a151jl1j6 would contain the messages and so on.
"chats":{
"a151jl1j6":{}}
"members":{
"a151jl1j6":{
"user1": true,
"user2": true
}
}
"messages":{
"a151jl1j6":{}}
The part where this gets is little "inefficient" is the querying for conversations that include both user1 and user2. The recommended way is to create an index of conversations for each user and then query the members data.
"user1":{
"chats":{
"a151jl1j6":true
}
}
This is a trade-off when it comes to querying relationships with a flattened data structure. The queries are fast since you are only dealing with a subset of the data, but you end up with a lot of duplicate data that need to be accounted for when you are modifying/deleting i.e. when the user leaves the chat conversation, you have to update multiple structures.
Reference: https://firebase.google.com/docs/database/ios/structure-data#flatten_data_structures
I remember I had similar issue some time ago. The way how I solved it:
user 1 has an unique ID id1
user 2 has an unique ID id2
Instead of adding a new chat by autoId chats/a151jl1j6 the ID of the chat was id1---||---id2 (superoriginal human-readable delimeter)
(which is exactly what you've originally suggested)
Originally, I put a reference to the other user as the value of the chatId key in the users/user/chats node, but I thought that was a bad idea in case I ever wanted group chats.
There is a saying: https://en.wikipedia.org/wiki/You_aren%27t_gonna_need_it
There might a limitation of how many userIDs can live in the path - you can always hash the value...