Deleting data in firebase 7 - javascript

Recently I came across a problem, I am making a function where you can get rid of chats in my app so I have this function
function deleteconvo() {
const me = firebase?.auth?.currentUser?.uid;
const members = [me, recipient.uid];
firebase.db.collection("conversations").remove({ members });
}
Firebase is telling me that:
firebase.db.collection("conversations").remove({ members }); is not a function
I also tried .delete and I cant find any answers online. Anyone have a solution to this?
note: I understand that I have to grab the docs value too, because I am in the conversation collection of the the database each conversation has its own unique ID, which I dont know how to grab and store that in a variable.

A good starting point is the official Firestore documentation regarding how to delete data.
In that page you can find examples in different languages on how to delete documents, fields and collections.
For example to delete an entire collection or subcollection in Cloud Firestore you need to retrieve all the documents within the collection or subcollection and delete them.
And to delete a document you can use the delete() method:
const res = await db.collection('cities').doc('DC').delete();
`

Related

Get all collections from a document Firebase

I'm building a fullstack todo app using firebase to store user information. My idea is that each user can create multiple lists and write multiple 'todos' in every list (eg. Have a list for today and another for tomorrow). My data is structured in this manner:
users (collection)
-> usersID (every user is a document)
-> todos Lists (collection) -> todoId (document) -> (object with the data)
I can't seem to be able to query the multiple lists a user might have (by default, I'm currently just retriving data from the 'todos' collection). Either I'm failing to see some firestore functionality or I'm not structuring my database correctly. Any advice?
You are structuring your data fine. The problem is that the Firebase Client SDK doesn't offer a function to retrieve all subcollections a document has. To solve your problem you got multiple options.
1. The cleanest but most exhaustive way
You upgrade to the Blaze Plan and use Firebase Functions with the Admin SDK. The Admin SDK offers a function called listCollections() which exactly does what you want. The disadvantage is that Firebase Functions have something called coldstart which means that when your function was idle for some minutes it takes up to 20 seconds (from my experience) to run again after you called it, which can be really frustrating. Otherwise you can run a free node.js server on something like Heroku to use the Admin SDK there to avoid coldstart (better option in my opinion). The Admin SDK is explicitly not meant to be used on the client side. Check this thread
2. List all your todo lists (easiest way)
Everytime the user creates a new list, you add that to an array in your users document like this:
// Representation of your user document
user
name: "Florian"
lists: [
"todos",
"anotherList"
]
So in that way you can just fetch your user, get the lists property from it and call all lists with a loop over the lists array. As alternative just display the lists content and let the user open it explicitly to save reads.
3. Restructuring your database (I would recommend it)
If you don't have a lot of data yet, I would recommend to restructure your database like:
users - the collection with all your users (without the todo list subcollections
lists - containing a document for every created list
- each document contains a field with `owner`
- each document contains a field with the list name
- each document owns a subcollection with todos
If you use this way you could just query the database like
const getLists = async () => {
const ref = collection(db, 'lists');
const q = query(ref, where('owner', '==', theUserYouWantToQuery);
// returns array with all list (including listname) of that user.
const lists = (await getDocs(q)).docs.map(doc => ({ ...doc.data(), doc.id }));
}
when you have all list objects from that user you can either loop over that array to get all todos in the lists or let the user only fetch one list by opening it

Reducing the amount of reads in a where query

I have recently implemented firebase into my project and I have created a user collection, this collection has a document for each user and each document has about 8 fields, when my user launches the app, I am trying to pull the document that corresponds to his data, so im doing the following query:
async function getUserData() {
const _collection = collection(db, "users")
const _query = query(_collection, where("userid", "==", uniqueUserID))
const querySnapshot = await getDocs(_query)
querySnapshot.forEach((doc) => {
console.log(doc.data())
})
setLoadingStatus(false)
}
This query works and gives me the corresponding user data, but the problem is, if the user is too far down the collection, this will execute 8 reads per document until it gets to the corresponding user, I have tried to implement a cache system using a lastModified but I still need to read the document data for that field and it will end up using more or less the same amount of reads. My question is: How do I reduce the amount of read operations that get executed when im trying to compare values in the documents, I have also thought of adding an a like so a_uniqueUserID so it gets ordered alphabetically and takes the first spot of the document but it's hacky.
EDIT: Here is what my structure looks like:
I think you are misunderstanding the definition of a document and a field. When you read a document, you always get all fields out of it. The snapshot contains everything read, even if you don't use it. There is no additional cost per field, other than the storage required to hold it all. In your screenshot, you show 5 documents, and one of those documents have 8 fields.
You are probably misunderstanding the metrics in the console. When you read and write documents using the console, those are also billed as reads and writes - use of the console is not "free". What you are seeing is a combination of what your app is doing in combination with what you're doing in the console.

Cloud Firestore: Get Value from collection ID if it exists

I want to obtain the value of a collection ID from a collection in cloud firestore if it exists:
export const getSlugs = async () => {
const document = await db
.doc(constDocumentRefs.slugs)
.collection('<collection_id>')
return ;
};
but this returns me collection reference, I can check if its empty by calling: document.get().empty method but not sure how do I get the value of collection, in case it is not empty.
My collection looks like this:
{
key1:1
key2:2
}
I want to keep it like return the actual value if collection exists otherwise return -1. Someone please help!
I can see two possible ways:
From the front-end:
As Dharmaraj mentioned in his comment, you need to fetch document(s) in the collection to see if the querySnapshot is empty or not. If the snapshot is empty, the collection does not exist. You can limit the query to only one document to minimize cost. For that you'll use the limit() method. And for checking if the QuerySnapshot contains a doc use the size property.
From a back-end:
The Admin SDKs offer a specific method to list collections, for example listCollections() for the Node.js Admin SDK (and listCollections() method of a DocumentReference for listing sub-collections). You can implement that in a Cloud Function and call it from your front-end: I wrote an article on this approach.

Firestore data modeling and angularFire

I have data model like this
Players-->root collection
Sports--->root collection
Players_Sports---root collection
I want get all the sports(Multiple sport) details or document player belongs.
For this I am using angularFireStore5
First, I am getting
Player details like this
this.db.collection('players').doc(id).get().toPromise()
Second, I am getting Player(user) linked PlayerSport
db.collection<any>('PlayerSports',ref => ref.where('playerId', '==', id) ).get().toPromise()
Third, I am trying to get Sports details based on ID'S,
db.collection<any>('sportsType', ref => ref.where('sportsType' 'in' [sportsIDs])).get().toPromise()
where SportIDs is arrary of ID that are linked in player_sports
First and Second steps works fine, but third steps is not giving any data or response
Could you please let me know where is the problem,
is it in Data model or code? my guess is that data model is not correct. Please guide me on this.
I would suggest getting the data from firebase and storing it inside a list so the app can access it later.
void getDataF(){
databaseReference
.collection("TableName")
.getDocuments()
.then((QuerySnapshot snapshot) {
snapshot.documents.forEach((f) {
iDFacList.add(f.documentID);
dbFacList.add(f.data["FieldName"]);
});
});
}
There is no sportsType field in the sportsType document as far as I can see.
If you're trying to find documents based on their SportsId field, you'll want ref.where('SportsId'....
Update
It seems that you're trying to find a document by its ID, which you can do with:
ref.doc(sportsIDs)
If you want to get multiple documents, or get a single document as a collection, you can use:
ref.where(firebase.firestore.FieldPath.documentId() 'in' [sportsIDs])

What is the best practice of firestore data structure?

I'm making a blog app using firebase.
I want to know the best practice of data structure.
As far as I know, there are 2 case.
(I'm using react native)
case 1:
posts
-postID
-title,content,author(userID),createdDate,favoriteCount
favorites
-userID
-favoriteList
-postID(onlyID)
-postID(onlyID)
In this case, for example, when we need to get favorite posts.
firebase.firestore().collection(`favorites/${userID}/favoriteList`)
.get()
.then((snapshot) => {
snapshot.forEach((favorite) => {
firebase.firestore().collection(`favorites/`).doc(`${favorite.id}`)
.get()
.then((post) => {
myPostList.push(post.data())
});
});
in this case, we can't order the favorite posts by createdDate. So, need to sort client side. Even if so, we don't use limit() function.
case 2:
posts
-postID
-title,content,author(userID),createdDate,favoriteCount
favorites
-userID
-favoriteList
-postID
-title,content,author(userID),createdDate,favoriteCount
-postID
-title,content,author(userID),createdDate,favoriteCount
firebase.firestore().collection(`favorites/${userID}/favoriteList`).orderBy('createdDate','desc').limit(30)
.get()
.then((snapshot) => {
snapshot.forEach((post) => {
myPostList.push(post.data())
});
});
in this case, When the favorite post is modified by the author,
we have to update all of the favorite posts. (e.g. If 100 users save the post as a favorite, we have to update to 100 data.)
(And I'm not sure we can increment favoritecount by a transaction, exactly same.)
I think if we use firebase.batch(), we can manage it. But I think it seems Inefficient.
It seems that both ways are not perfect. Do you know the best practice of this case?
What about using arrays or Collection Groups?
solution 1: arrays
posts
-postID
-title,content,author(userID),createdDate,favoriteCount
-[favoriters(userID)]
Now you can query for a user's favorites by querying posts that "array-contains" the user's ID. You can also modify individual posts without iterating through a bunch data copies.
There's a limit to this approach though. Maximum size for a document is 1 MiB; assuming that a user ID is 4 bytes, a document can contain no more than 250K favoriters. Clients would also have to do some O(N) processing to add / remove favoriters.
solution 2: Collection Groups
posts
-postID
-title,content,author(userID),createdDate,favoriteCount
-favoriters {collection}
-userID
A collection group consists of all collections with the same ID. By default, queries retrieve results from a single collection in your database. Use a collection group query to retrieve documents from a collection group instead of from a single collection.
So we can fetch a user's favorite posts via
db.collectionGroup("favoriters").whereEqualTo("userID", <userID>).get();
To favorite a post, we just do
const postsRef = db.collection("posts");
postsRef.document(<postID>).collection("favoriters").add({ "userID", <userID> });
Maybe not a direct answer to your question, but the official documentation has an example for that:
Working with arrays, lists, and sets
Summary: Store and query data in array-like structures in documents.
Use case: If your app requires complex data objects like arrays,
lists, or sets, follow the model outlined in this solution. For
example, in a blogging app, you might want to create a set of related
posts.
https://firebase.google.com/docs/firestore/solutions/arrays

Categories