i am building a small web app with MERN, i have a collection that holds "name, email, password, avatar url, and date" and i am going to add to the users some info like a "bio, hobbies(array), "visited countries(array), and another array"
question is, should i create a diffrent model for the users info, and add owner field that refers to the other model?. or should i put all of them there,
also i might add the following and followers option in the future.
The user's info should be in the user collection, I could see there is no reason to have a separate collection for it. If you want to reduce the responses from listing users, you could use populate to remove unnecessary fields.
Regards to the following and followers, I think there are 2 approaches:
Adding a new field which used to store id and necessary metadata (name, avatar) of users to the existing collection
Create a new collection which is a combination of users and users they are following, or are followed. You then could use Virtual to get this information from the User collection.
Personally, I prefer the first approach although it requires more effort to maintain the list to be accurate. E.g remove an item out of the list when your follower stops following you.
Related
It's my first time working with FireStore. I'm working on a ridesharing app with Flutter that uses Firebase Auth where users can create trips and offer rides similarly to BlaBlaCar, where other users can send requests to join a ride. I’m having difficulty not only deciding the potential collections and paths to use, but also how to even structure it.
For simplicity at this stage, I want any user to be able to see all trips created, but when they go to their “My Rides” page, they will only see the rides that they’ve participated in. I would be grateful for any kind of feedback.
Here are the options I’ve considered:
Two collections, “Users” and “Trips”. The path would look something like this:
users/uid and trips/tripsId with a created_by field
One collection of “Users” and a sub-collection of “Trips". The path seems to make more sense to me, which would be users/uid/trips/tripId but then I don't know how other users could access all the rides on their home feed.
I'm inclined to go with the first option of two collections. Also very open to any other suggestions or help. Thanks.
I want any user to be able to see all trips created, but when they go
to their “My Rides” page, they will only see the rides that they’ve
participated in
I make the assumption that participating in a ride is either being the author or being a passenger of the ride.
I would go for 2 collections: one for users and one for trips. In a trip document you add two fields:
createdBy with the uid of the creator
participants: an Array where you store the author's uid and all the other participants uids (passengers)
This way you can easily query for:
All the rides
All the rides created by a user
All the rides for which a user is a participant, using arrayContains.
(Regarding the limit of 1 MiB for the maximum size for a document I guess this is not a problem because the number of passengers of a ride shouldn't be so huge that the Array fields size makes the document larger than 1 Mib!)
Note that the second approach with subcollections could also be used since you can query with collections group queries but, based on the elements in your question, I don't see any technical advantage.
I'm currently working on an application where users can create groups and invite others in it.
I would like people in the same group to be able to see their first and last names.
To do that, I have a collection named Users where each of the users have a document contains all their personnal data, like first and last names, phone, position , ...
I have also another collection named Groups, where all of my groups are stored, with their name, and an array contaning the ID of the members.
When an user open the app, a first request is done for request his groups (he recieve the groups names and the arrays of members). After, if he want to know the user in a certain group, another request is done for search only the first and last name of all the members.
So, I imagine that there is a query that will return me only the fields that I would like to retrieve, and that there is a rule allowing a potential hacker to be refused access to the entire user document except if the user is the owner of the document.
// For retrieving my user's groups
Stream<List<Group>?> get organizations {
return firestore
.collection('Groups')
.where('members', arrayContains: this.uid)
.snapshots()
.map(_groupsFromSnapshot);
}
// For retrieving names of the members of a group
Stream<List<Member>?> getMembers(Group group){
return firestore
.collection('Users')
// and i dont know what to do here ...
}
With the Client SDKs and the Flutter plugin it is not possible to get only a subset of the fields of a Document. When you fetch a Document you get it with all its fields.
If you want to get only a subset of the fields of a document, you can implements the two following approaches:
Denormalize your data: You create another collection which contains documents that only contain the fields you want to expose. You need to synchronize the two collections (the Users collection, which is the "master", and the new collection): for that it's quite common to use a Cloud Function. Note also that it's a good idea to use the same documentID for the linked documents in the two collections.
Use the Firestore REST API to fetch the data: With the REST API you can use a DocumentMask when you fetch one document with the get method or a Projection when you query a Collection. The DocumentMask or the Projection will "restrict a get operation on a document to a subset of its fields". You can use the http package for calling the API from your Flutter app.
HOWEVER, the second approach is not valid if you want to protect the other users data: a malicious user could call the Firestore REST API with the same request but without a DocumentMask or a Projection. In other words, this approach is interesting if you just want to minimize the network traffic, not if you want to keep secret certain fields of a document.
So, for your specific use case, you need to go for the first solution.
I am struggling to find the right solution in flutter to get the values of my user's sub-collection in Cloud Firestore!
This is my user holding the collection "affiliations"
These are the contents of the sub-collection "affiliations". In this case there are two references to organizations.
At runtime I would like to identify if a specific user is connected to an organization (organization key appears in referenced document).
So I have the user id and the organization id. How would you solve this?
Cheers!
So if I understand you correctly, the path would be:
firestore.collection('users')
.doc(user_id)
.collection('affiliations')
.doc(organization_id)
.get().then((snapshot){
//do something with your snapshot
});
Above is the recommended way but I see you would need to rename your documents in organization to be the organization id.
What you could do but is unnecessary:
firestore.collection('users').
.doc(user_id)
.collection('affiliations')
.where('organization', isEqualTo: 'organization/idstring')
.get((querySnapshot){
//do somthing here
});
If a specific user can only be affiliated with a specific organization once, I recommend using the organization ID as the document ID for that affiliation too. That way you don't have to query, but can directly check if a document with that ID exists.
While it may not make a big performance difference, it will keep your data more readable and allow you to check whether the user is affiliated with an organization in your security rules - something that isn't possible in your current structure.
I have a collection of "quizes" that users will participate in. When a user takes a quiz I create a document in "results" collection for with that userId and quizId. I want my app to pull all docs from "quizes" collection excluding the ones that the user taken. In SQL I would do "NOT IN" clause and accomplish that, but I have no idea how to best approach this in Firestore.
There's no equivalent query in Firestore. You would need to pull all the data and determine which docs are relevant on clientside.
Alternatively, you can create a list of all quizzes for each user and maintain this list. You could add and remove quizzes for each user as they become relevant/irrelevant to show them.
What's the best way to get a list of documents based on another list of document ids?
If I have User and Profile objects.
Users have a single Profile
Users can save other users' profiles
The same profile can't be saved twice
The documents of the savedProfile sub collection are stored based on the uid of the user it belongs to. It also has an attribute of userRef which stores the uid of the user again. Given that savedProfiles is a list of uids. Is there a way to get a list of profiles based on the savedProfiles subcollection? Currently I am able to make a get request for a users saved profiles which returns a list of uids which I store in a variable. I'm just wondering how I would make the next request to get the full profiles of the savedProfiles based on that list? Saving the whole user profile in a users savedProfiles is also not an option since these profiles can be updated and changed quite frequently and it would be expensive to find and change each users saved profiles if that profile has been saved. (If there was 100,000 users with an average of around 10 saved profiles each).
Please tell me if there's a way to make this sort of query or if there's a better way to structure my data. Thanks.
Ok, so I think I managed to find a way. From my cloud function I used admin.firestore().getAll(refList). refList is an array of document references that I want. This returns a promise which gives a list of documents matching those references. The data for each document is accessible like normal with doc.data() I've either solved the problem, or I'm doing something very wrong. Feel free to comment and let me know if what I'm doing is okay. Thanks