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.
Related
Viewed the Firestore docs + Google's I/O 2019 webinar, but I'm still not clear about the right data modeling for my particular use case.
App lets pro service providers register and publish one or more of their services in pre-defined categories (Stay, Sports, Wellness...) and at pre-defined price points (50$, 75$, 100$...).
Users on the homepage are to filter down first with a price point slider - see wireframe), e.g: 199€, then and optionally by selecting the category, eg: all 'Sports' (at 199€) and the location (e.g: all sports at 199€ in the UK). Optionally because users can also build their list with a button as soon as the price is selected. The same 'build list' button is after the category selection and after the location selection. So 3 depths of filtering are possible.
What would be the ideal data structure, given that I want to avoid thousands of reads each time there's filtering.
Three root-level collections (service providers, price points, service categories?) with their relevant documents? I understand and accept denormalization for the purpose of my filtering.
Here's the wireframe for a better understanding of the filtering:
App lets pro service providers register and publish one or more of their services in pre-defined categories (Stay, Sports, Wellness...) and at pre-defined price points (50$, 75$, 100$...).
Since you're having pre-defined categories, prices, and locations, then the simplest solution for modeling such a database would be to have a single collection of products:
Firestore-root
|
--- products (collection)
|
--- $productId (document)
|
--- name: "Running Shoe"
|
--- category: "Sport"
|
--- price: 199
|
--- location: "Europe"
|
--- country: "France"
In this way, you can simply perform all queries that you need. Since you didn't specify a programming language, I'll write the queries in Java, but you can simply convert them into any other programming language. So for example, you can query all products with a particular price:
FirebaseFirestore db = FirebaseFirestore.getInstance();
Query queryByPrice = db.collection("products").whereEqualTo("price", 199);
If you need to query by price, category and location, then you have to chain multiple whereEqualTo() methods:
Query queryByPrice = db.collection("products")
.whereEqualTo("price", 199)
.whereEqualTo("category", "Sport")
.whereEqualTo("location", "Europe");
If you, however, need to order the results, ascending or descending, don't also forget to create an index.
What would be the ideal data structure, given that I want to avoid thousands of reads each time there's filtering.
If you don't need to have all the results at once, then you have to implement pagination. If you need to know the number of products that exist in the sports category ahead of time, that is not possible without performing a query and counting the available products. I have written an article regarding this topic called:
How to count the number of documents in a Firestore collection?
Another feasible possible solution would be to create a single document that contains all those numbers. In other words, exactly what you're displaying to the users, everything that exists in those screenshots. In this way, you'll only have to pay a single read operation. When the users click on a particular category, only then you should perform the actual search.
I understand and accept denormalization for the purpose of my filtering.
In this case, there is no need to denormalize the data. For more info regarding this kind of operation, please check my answer below:
What is denormalization in Firebase Cloud Firestore?
I have a Google Firebase Realtime Database with the following structure:
project
|
- users
|
- uid_1
|
- name
- age
- ...
|
- uid_2
|
- name
- age
- ...
I'm new with Google Firebase. I can read all db-fields from a specific 'uid'. But how can I collect all names from all unsers? I want to make an file-uploader and to assing the file to an existing user, I want to use a dropdown-menu to select the user.
With the way you have this data structured, you're going to have to write code to query everything under "users", iterate the children, and pull the names out of each child.
Realtime Database doesn't offer any sort of SQL-like projection type query that will get you just the vales of certain children. Or to put it another way, you can't do anything like "select name from users". If getting only the name is a common operation for you, you will need to duplicate only the names into another parent node, and query that new node instead.
The Firebase Admin SDK allows retrieving the entire list of users in batches. But max result is 1000.
Or you can denormalizing your data.
Understanding the speed of Firestore reads, I'm curious what others Firestore users do when they need to take a current object (in my case a user) and see how that user relates to many other objects (other documents).
My use case currently is a user signs in and goes to see a list of items (5 items on initial page load). Each item has many options like "Liked" or "Favorited."
To see if a user has liked each item, I can either store a single document containing a list of all items a user liked for each category of items, or I can make a call to fetch the document storing the "user A liked item X" which would be numberOfItems * numberOfValues (e.g. 5 items, each item has 3 different boolean options).
Curious what others do in this case to keep document read count tamed.
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’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
.
.
.