Firestore contacts list data model [closed] - firebase

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 2 years ago.
Improve this question
I am working on a management app for local groups.
The app also displays each group its contacts list.
I wonder how should I design my database?
If I store all users on a root level collection, each time a user opens the contacts list it will read all his group's users' documents. Assuming 1000 contacts groups, for example, adds up to A LOT of reads for a simple task like that.
The same goes for using a subcollection for the group.
Storing the group's contacts in the group's document as a map is not scalable.
And the same goes for using a map in the group's document to index a collection or a subcollection in a denormalized model.
And this is where I'm stuck.
Am I missing something or that these are the options I have and I need to choose between a large number of reads each time a user opens the contacts list and a model designed for limited sized groups?

I think this is a common situation. Many items are related to fewer parent items, and we want to show the parent item's children.
For Firestore, it's recommended that you limit your queries.
For example, if a user wants to see the groups' contact list, that's fine, make a query. But don't show all 1000+ contacts at once. Even Facebook doesn't do that (go to a Facebook group and click on "Members", you'll only be shown a dozen or so, and as you scroll down, more queries are made to show you more.)
Users expect this kind of behavior: lazy loading or pagination.
Documentation for Firestore to limit/paginate queries: limit, paginate
This way, groups can be documents, and contacts can be documents that have an Array field that contains the group-id's they belong to. To display a group's contacts, you can use an "array-contains" query on the contacts collection.
Something like this
contacts (collection)
|
--- {contactId} (document)
|
--- (...contact data...)
|
--- group_membership (array)
|
0--- 'groupId111'
|
1--- 'groupId222'
(For the contacts(col)/contact(doc)/group_membership(field) I'm assuming a contact can belong to multiple groups if this is not the case, the field can be a string instead of an array, but it's safer to make it an array in case you change your mind.)
All I'm getting at here is that your vision for the db structure is fine and common, you don't have to restructure just to avoid querying a thousand contact documents... because you don't have to. You don't have to query 100 times the amount of data that your end-user will actually need.

Related

How to setup data structure for real estate app in Firebase [closed]

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 2 years ago.
Improve this question
I'm planning to build a MVP for a real estate system using React and Firebase. I have used SQL databases in the past and hence find it difficult to understand the NoSQL concepts (collections, documents, fields).
Below are the tables I would set up in an SQL database and wanted to know how to set up the fields in Firebase. The front end client should not download irrelevant documents and we should be able to query documents across collections.
For example: What's the property address of a particular household member.
Property
PropCode
Start Date
End Date
Property Type - (House, Unit, Villa)
Property Source - ( Developer, Housing, Self)
Address ( State, Post Code\Zip Code, Suburb, Street)
Tenancy
TenancyID
PropCode - Links to the property table
Tenancy Start Date
Tenancy End Date
Tenancy Type (LongTerm, Short Term)
Household
HHID - The household ID
HHMID - The household member ID. Each member in the household is assigned an ID
FirstName
LastName
DOB
Email
HHM Start Date
HHM End Date
Household-Tenancy - Table to link household with Tenancy
TenancyID
HHID
Thanks
Jag
Well, this question is really having a vast scope and it cannot be entirely covered in one answer.
Here is my try to give you a starting point:
Note: This is for Firebase Firestore (not Realtime Database).
Firebase Firestore Schema (Brief):
In firebase, you have a collection which simply can be said as a bunch of documents. Now, what are documents? Documents are the actual place where your data reside. So for eg., you will have a collection named users which would have all the users' documents (data).
Refer here for more details: Firebase Firestore Model
Your Answer (a try):
Collection-Properties: which would contain all of the properties' documents. Each document would contain data of the property (address, unit etc..). It would also contain the type of the Property (room, house etc.) and the UID (the unique ID of a user in Firebase) of the current tenant (By this you can query for the user using his UID in the Tenants collection). The document would also contain a subcollection- Previous Tenants which would contain the documents with details of the previous tenants.
This would also contain all the demographic details of the properties, (a subcollection is recommended not a separate collection).
NOTE: Firestore document can contain at maximum 1mib, so if there is possibility of exceeding that limit then you can break down the details into subcollections.
Collection- Tenants:
which would contain all the tenants' documents. Each document would contain data of the tenant (name, rent etc) and the document ID of the property in which he is currently living (By which you can query the property). Also, it would contain a subcollection-Previous Properties which would have the details of the previous properties in which he lived.
I'm not quite sure about what you mean by rent statement but if it just means the total rent the tenant has to pay in a week, you can directly have a subcollection which would contain the tenant's weekly rent.
I hope I was able to cover you listed assets. In these cases, no one can say a correct or a wrong data structure. You just need to think of the one, which suits you best.
Additional Bonus: Advanced Data Modeling with Firestore by Example

Randomly pairing users in Firebase [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I'm developing an application using Flutter and Firebase and I have to solve a problem that sounds like this:
each user (at any time) can put himself in a waiting list
Firebase has to handle the waiting list by creating (randomly) pairs of users
My idea is to have a collection in the Cloud Firestore for the waiting list in which each user is a document and a cloud function that reacts to the document creation by searching for an other user (document) in the collection, deleting both documents (i.e. removing the users from the waiting list) and creating another document in another collection that represents the pair.
The main issue is to design (if possible) a transaction in order to guarantee that two or more executions of the same cloud function do not overlap.
Any suggestion? Or any other way to solve this problem?
Thanks!
You could put all the users in a single document with Unique ID and data like following:
Then you could use a Cloud Function and that will execute following things:
Retrieving the Array called waiting from a specific document. It
will add new account user id to that array.
If the array has got at least 2 elements. It will add a new
array of maps named paired from the 2 elements from the waiting list and
add the value to firestore. It will call the existing paired
array and add the new 2 elements and save it to Firestore. Also update the paired_with field in
users doc.
It will remove the 2 elements from waiting list update an empty
list.

Firestore : how to read efficiently with a large amount of data [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 3 years ago.
Improve this question
I'm trying to find a good way to read a large amount of data in firestore. Currently , I have 10000 documents in a single collection "movie". These documents are records that contains fields about a movie ( author , title , id).
My client use a query to read 20 documents randomly with .limit(20) and a user can fire this query as the much as he wants to get new documents. The problem is that an user can ask for example for 1000 documents(movie) and this cost 1000 reads in firestore.
I was thinking if it's possible to reduce the numbers of reads by structuring my collection in a different way with for example 500 subcollections with 20 documents(movies) inside. Like this, I have my documents divided equally and my client can just read 1 subcollection that contains 20 documents. Does this reduce the number of reads to only 1 ?
You're saying:
My client can read 20 documents randomly using .limit(20) and when a user click on a button 20 new documents are read once again. The problem is that an user can ask for 1000 documents and this cost 1000 reads in firestore.
If you want to limit the user to read at most 20 documents at once, you can do so in the server-side security rules with:
// Limit documents per request to 50
allow list: if request.query.limit <= 20
Also see the reference documentation on the query object in security rules.
Of course this only limits the number of documents the user can request at one time. They can still perform 50 queries of 20 documents each, and get 1000 documents that way.
The only way to have fewer reads is to read fewer docs. This is true for sub-collection, too. One way to have fewer docs is to fill single docs with more data...
// in a single doc
movies: {
movie_id_a: { title: 'Gone With the Wind', rating: 'G' },
movie_id_b: { title: 'Casablanca', rating: 'PG' },
...
}
But this comes at a cost: You'll run into a doc size limit, and you won't be able to use database features associated with keeping logical chunks each in their own doc (like saving a reference to just one movie, or listening to just one movie, etc)

How to exclude certain data from Firestore query

I want to populate my FirestoreUI recyclerview with the 5 most popular users in that database (By sorting "subscribers"), but at the same time check if the user has already added them as a friend by checking if the user-id of the famous person is already under the "friends" collection under their own user-id document.
Is there a way of excluding a user which has already been added? Is this also possible while having 5 entries?
If you need to check against data that's in multiple collections, you won't be able to do that with a single Firestore query. (There are no "join" queries in Firestore.) You also can't write queries to selectively exclude certain values from fields.
With your current structure, you will have to first load up all the relevant friends in memory. Then you could set up a paged query for users, and page through it until you find enough documents that match your criteria that you check individually in client code.

Firestore : How to design a Data model to make querying documents that are not exist in an array possible?

I'm trying to find a way to properly desing my Data Model with Firestore. I'm looking for something similar to what Tinder does, showing you people that you have'nt swiped yet, based on your location.
So I ended up with something like :
A User1 has an array of "met people"
A "Haven't yet met user"/ User2 his also a User with the same document model
They all belong in the same "Users" collection
I want to query all the users that this User1 haven't swiped yet
I know that you can't do something like "array_not_contains" or "!=" because all fields that you query need to be indexed.
So I wonder, is this possible to model data to make it work, or the only solution is to drop Firebase because this kind of query is not possible at all?
One alternative can be to store in a collection all the relationships (with theirs status) between all users. But that also means that whenever a user signup, I have to create as many documents as I have users that's really ugly and make a enormous numbers of documents.
EDIT:
Thanks again for your answer and sorry for my late answer.
There is no need to create a new database call since you already got all the users from that area in the first place.
Not If have a large response set, I will limit to a number. (5 in the example below).
And even If I don't limit the number, in the next db call, how I can know that new peoples has been added and how to retrieve only those.
I will not remove them from Users Collection has they can be show to others users.
P.S: I forget User4 in Users Collection pictures.
For User 1, get 5 first matchs, remove existing ones, show User5.
For User2, get 5 first matchs, remove existing ones, show User4, User5.
After users choices, Users are added to their list. Users Collection stay the same.
For User 1, get 5 first matchs, remove existing ones, nothing to show, even if I have a User 6, 7.
To fix that I launch a second query get the new ones but, more the user use the app more query I may need to do to try to display to him existing user in his area.
Maybe I've misunderstood what you named "initial list", for me it is the list object retrieve from my db containing all users (with limit).
EDIT 2:
You can check the answers of Alex Mamo to know how to query documents that are not exist in an array possible.
Let's me explain my use case and why I think, that won't work.
I want to be able to search all users next to me, for trying to do that in Firebase, I store Geopoint. Geopoint can't be really use for now out of the box with Firebase, so I user Geofirestore in a Cloud Function.
I store and update user Geopoints based on theirs locations, so this means user location change by time.
I limit the numbers of Users return by this function.
In my initial state I retrieve users next to me (User1), I get 3 an 4.
Let's say that I store last checked userId to use it later as a cursor for my query (User 4).
Now my geopoint change, and the users in this area changes too.
I request next bunch of users next to me, and I use my previous userId/document to "startAfter" (more on this
here), see the image below, that's won't work.
If I use the cursor (User4), I'll take 5, but not 2, because in the return list, if I order by Id, 2 will be before 4.
Worse, like below, if the return list may not even have user 4 in it, the cursor will be pointless.
My example is a bit simplified and does not take in account what is described in the first answer and my first edit (limited subset of users, data design).
A possible database structure for your app might be:
Firestore-root
|
--- users (collection)
|
--- uid (document)
|
--- acceptedUsers: ["uidOne", "uidTwo"]
|
--- declinedUsers: ["uidThree", "uidFour"]
|
--- //Other user properties
The mechanism is simple. When you first want to show a user profile to the current (authenticated) user, you have to create a query that will return all users (in user area). According to the user decision, you need to add the corresponding uid in either the acceptedUsers array or in declinedUsers array. Once you want to show another users, use the same query but this time, you need to make an extra operation. Once the query returns the users within user location, add all those users to a list. Compare the list that is coming from the database with your exting arrays and remove all the users from both arrays. In this way you'll have a list that contains only users that the actual user didn't see. This extra step is needed to make sure the id of the user does not exist in one of those arrays. In the end, simply choose a random user from the list and show the details to the user. That's it!
One alternative can be to store in a collection all the relationships (with theirs status) between all users. But that also means that whenever a user signup, I have to create as many documents as I have users.....that's really ugly and make a enormous numbers of documents.
This is not an option. This means that you need to write each time a user joins your app an enormous amount of data, which will be very costly. Since everything in Firestore is about the number of read and writes, I think you should think again about this approach. Please see Firestore usage and limits.
Edit:
Let's consider the initial list of users that has 10 records. With other words, all the users within that area are 10. You say that 7 users are already seen, that makes the list contain only the 3 remaining users.
So I display the 3, (or I do another request to get some more) and he check the 3.
Yes, you should display those 3 users and then remove them one by one from the initial list. There is no need to create a new database call since you already got all the users from that area in the first place. Once the list remains empty, you should display a message to the user that in that particular area are no more users to swipe.
When will create another database call?
Only when needed. Which means that you create another call once new users enter that area. Let's say 3 new users are new, you get a list now of 3 user and use the same algorithm.
More my user use the app more it’s difficult to show people that he haven’t seen, because his list become bigger.
If you think that the arrays will grow more than a document can hold, then you should consider storing the users in a collection and not in an array. So in this case, the problem is that the documents have limits. So there are some limits when it comes to how much data you can put into a document. According to the official documentation regarding usage and limits:
Maximum size for a document: 1 MiB (1,048,576 bytes)
As you can see, you are limited to 1 MiB total of data in a single document. When we are talking about storing text (uids), you can store pretty much but as your array getts bigger, be careful about this limitation.
But if you'll stay within this limits, which I personally think you'll do, you have nothing to worry about.
Edit2:
Not If have a large response set, I will limit to a number. (5 in the example below). And even If I don't limit the number, in the next db call, how I can know that new peoples has been added and how to retrieve only those.
I will not remove them from Users Collection has they can be show to others users.
If you have large amount of data (many users in a single area), yes it's good idea to limit the results, but a much better idea would be to load the data in smaller chunks. In short, get 5 users, remove one by one till the list has zero users, load other 5 users and so on. This can be made using my answer from the following post:
Is there a way to paginate queries by combining query cursors using FirestoreRecyclerAdapter?
The initial list, is the list that you are getting when you first query the database. In this case, the initial list will contain 5 users.

Resources