Cloud function to find and delete deleted user id in every sub-collection - firebase

Q. What's the best practice to find and remove a deleted user id from different sub-collections friends under each user id in users collection?
Assumption
This is an example data structure.
- users [collection]
- user A [document]
- friends [sub-collection]
- cqeDIDZhOtf7DmGX42XPs6jwjX22 [document]
- user B
- friends
- cqeDIDZhOtf7DmGX42XPs6jwjX22
User cqeDIDZhOtf7DmGX42XPs6jwjX22 has removed from the cloud function below.
exports.deleteUser = functions.auth
.user()
.onDelete(event => {
// perform desired operations ...
});
Q. What's the most efficient way to write a cloud function which finds a match with the following user id cqeDIDZhOtf7DmGX42XPs6jwjX22 in friends sub-collection and removes from the Firestore?

You're going to have to iterate all your user documents, then delete the document in each friends subcollection with the id of the user that was deleted. There's no way to have a single query span multiple collections - you're going to have to reach into them all individually.

Related

Nested snapshot listeners

I use Google Firestore for my iOS app built in Swift/SwiftUI and would like to implement the Snapshot listeners feature to my app.
I want to list all documents in debts collection in realtime by using snapshot listeners. Every document in this collection has subcollection debtors, which I want to get in realtime for each debts document as well. Each document in debtors has field userId, which refers to DocumentID in users collection which I would also love to have realtime connection on (for example when user changes his name I would love to see it instantly in the debt entity inside the list). This means I must initialize 2 more snapshot listeners for each document in debts collection. I'm concerned that this is too many opened connections once I have like 100 debts in the list. I can't come up with no idea apart from doing just one time fetches.
Have anyone of you ever dealt with this kind of nested snapshot listeners? Do I have a reason to worry?
This is my Firestore db
Debts
document
- description
- ...
- debtors (subcollection)
- userId
- amount
- ...
Users
document
- name
- profileImage
- email
I uploaded this gist where you can see how I operate with Firestore right now.
https://gist.github.com/michalpuchmertl/6a205a66643c664c46681dc237e0fb5d
If you want to read all debtors documents anywhere in the database with a given value for userId, you can use a collection group query to do so.
In Swift that'd look like:
db.collectionGroup("debtors").whereField("userId", isEqualTo: "uidOfTheUser").getDocuments { (snapshot, error) in
// ...
}
This will read from any collection name debtors. You'll have to add the index for this yourself, and set up the proper security rules. Both of those are documented in the link I included above.

Allow users from different collection see a different stream

I have an Orders collection. It contains a field called venueId. And I'm querying against this field using isEqualTo. The venueId is the firebase user uid. I also have a venues collection. It contains this venueId and also has a list of VenueAdmins ids(These ids are also firebase user uids )The app is a point of sales app(pos). I need to query the orders collections so that valueAdmins and venueId see the correct stream. Is quite easy to query with venueId.. venueId,isEqualto, uid. I'm wondering what's the best approach to allow the venueAdmins see the stream as well.
|-Orders // collection
order. //doc
venueId:'2344567788999999'
|-Venues // collection
venue. //doc
venueAdmin: ['3333333333333','55555555555555555']
venueId:'2344567788999999'
My query builder so far: queryBuilder: (query) => query.where('venue.id', isEqualTo: uid)
Firestore does not have the capability to "join" documents from different collections in a single query. A single query can only consider documents in single collection at a time. The way you have your data structured now, it will require at least two queries. First, to find a venue, then second, to find the orders for an admin in a venue.
The only way to make this easier from the perspective of queries is to denormalize your data by duplicating venue data into the order documents. If each order also had a list of admins, then you could reduce this down to a single query.

Saving users scores and favorites in Firestore Database

I am working in a small project that uses Firestore database as a backend. I explain about the database so it is understood what I need:
Basically I have a collection that contains a list of documents where each one of them represent a game. For each game I have the name, cover image, info, category, etc.
I also have a collection of the users, where I have the specific UID for each user (retrieved from the auth section), email, etc.
What I want now is to save the score that some user may have in some of these games, as well as the favorite games that the user could save. What I don't get to understand is how to create the connection between the users and the games. For example, I thought that I should save the users score creating a collection within each document(game) in the first collection that mentioned. But when I create this collection with ID "scores" it asks me for the first document where I have to facilitate an ID (if not automatic) and then I don't know how to proceed.
I have read also that I would have to create additional collections in the root folder like "favorites" or "scores" specifying the UID of the user but, how do I connect the user UID, the score, and game which the user got that score from?
I hope I explained myself properly. Thanks.
Firstly, I agree with Doug's comment above. The Firestore tutorial videos are a great resource!
In terms of connecting data to your user, you have some options. You can either:
Create sub-collections under each user. Such as /users/{user_id}/favorites. Favorites could be a sub-collection or an array of game_ids depending on your use case.
Store a userID field in the documents in a top level "scores" or "favorites" collection. Then you can query for scores in the /scores collection by adding a where userID == {user_id} clause to your query of the /scores collection.

Store and Query Posts in Firestore in a performant way

So I need to store Posts that are created by Users, now the data modell is the problem, bringing all existing Posts in a Posts Collection with a field of creatorUserID will make it able to show posts belonging to a user.
Now a User has a Subcollection called Followers with the ID of people following, the problem with that is that Im not sure how a query would look to show only Posts of People that the User follows.
Also im worried about performance when there are 10mio+ Posts in the collection.
In order to query a document in Firestore the data you want to query by needs to be on the Document you want to query, there is no way of querying a collection by the data of a document from another collection. This is why your use-case is a bit tricky. It might not seem very elegant, but this is a way of solving it:
We use two collections, users and posts.
User
- email: string
- followingUserIDs: array with docIds of users you are following
Posts
- postName: string
- postText: string
- creatorUserID: string
To find all the posts belonging to all the users the logged in user is following, we can do the following in the code:
1 Retrieve the logged in user document
2 For each id in the "followingUserIDs" array I would query Firestore for the Posts. In JavaScript it would be something like:
followingUserIDs.map(followingUserId => {
return firestore.collection('Posts', ref => ref.where('creatorUserID',
'==', followingUserId));
})
3 Combine the result from all the queries into one array of posts

Enforcing unique userIds in Firebase Firestore

I'm playing around with the new Firestore database from Firebase and was wondering if there was a more efficient way to enforce unique usernames (or unique child nodes).
I use email/password auth but allow users to create a unique handle, like Twitter.
With the Realtime database I was able to achieve this with transactions and a multiple node structure.
-users
-uid1234:
-username: ryan
-usernames:
-ryan: uid1234
I was thinking it may be possible to do this without the extra usernames node using documents as the username in Firestore.
You could do it probably do it in 2 ways. Check with a separate call before create user, if the user exist in an collection with usernames.
Also you could create a rule like:
match /users/{document=**} {
allow create: if !exists(/databases/$(database)/documents/usernames/$(request.resource.data.username));
}
In that case you get a error back if the username already exist on creating and that you can catch in the code.

Resources