Google Cloud Function to delete sub-collections on "missing documents - javascript

I have a Firestore collection called Posts, and each document in Posts could have a sub-collection called Post-Likes and/or Post-Comments. When I delete the Posts document, it does not delete the sub-collection so I am left with a reference to a missing document in Firestore which looks like this:
I am using the following code in my Google Cloud Function to find references in the Post collection with missing data, then for each document with a missing reference, I want to delete the sub-collections Post-Likes and Post-Comments. For now, I am just try to list the sub-collection document so I can delete them, but I am getting an error.
function deleteOrphanPostSubCollections() {
let collectionRef = db.collection('Posts');
return collectionRef.listDocuments().then(documentRefs => {
return db.getAll(...documentRefs);
}).then(documentSnapshots => {
for (let documentSnapshot of documentSnapshots) {
if (documentSnapshot.exists) {
console.log(`Found document with data: ${documentSnapshot.id}`);
} else {
console.log(`Found missing document: ${documentSnapshot.id}`);
return documentSnapshot.getCollections().then(collections => {
return collections.forEach(collection => {
console.log('Found subcollection with id:', collection.id);
});
});
}
}
return
});
}
However, I am getting the following error. Please help me resolve this issue.

This is because there is not getCollections() method for a DocumentSnapshot.
If you want to list all the collections of the Document corresponding to the DocumentSnapshot, you need to use the listCollections() method, as follows:
documentSnapshot.ref.listCollections()
.then(collections => {
for (let collection of collections) {
console.log(`Found subcollection with id: ${collection.id}`);
}
});
In addition, note that if you call an asynchronous method in a loop, it is recommended to use Promise.all() in order to return a single Promise that resolves when all the "input" Promises are resolved.

Related

Firebase React: Remove Item (Map) from array in firestore

I'm trying to remove a map item from an array in firebase. From what I understand with firebase - you are unable to delete the item based on the index. Should I structure this a different way or is there an easier way to remove a specific object from the array? Thank you
Error: 'No document to update: '
const listingRef = doc(db, 'users', 'savedListings');
const deleteListing = async () => {
try {
await updateDoc(listingRef, {
savedListings: deleteField()
});
} catch (e) {
console.log(e.message);
}
};```
The doc() takes path to a document that should be users/test#user.com in this case. While you can use arrayRemove() to remove elements from an array field you cannot delete an object from an array unless you know the exact value that object including all the fields.
const listingRef = doc(db, 'users', 'USER_EMAIL'); // USER_EMAIL is document ID
const deleteListing = async () => {
try {
await updateDoc(listingRef, {
savedListings: arrayRemove("THAT_OBJECT")
});
} catch (e) {
console.log(e.message);
}
};
If you don't have that exact object, then you'll have to read the document, manually remove the element from array and update the document back.

Delete document in firestore when value of document matches

Im having a bunch of documents in a collection in firestore. What I want to archieve is to search the documents by a "timestamp" property, after that I want to delete exactly this document.
My code looks right now like this:
firebase.firestore().collection("chatrooms").doc(`${chatId}`).collection(`${chatId}`).where("timestamp", "==", timekey).get().then((QuerySnapshot) => {
if (!QuerySnapshot.empty) {
QuerySnapshot.forEach((doc)=>{
console.log(doc.data().value)
});
} else {
// doc.data() will be undefined in this case
console.log("No such document!");
}
});
It is not deleting anything yet, its only returning me the value of the found document in my collection so I can see if the .where() call even works. Im having trouble to combine this .where() together with .delete() and I am not even sure if that is possible. Does anybody have any idea how to accomplish this task?
I can't see .delete() in your code. Also you cannot combine .delete() and .where(). You need the document IDs or the references to them. You can try this:
firebase.firestore().collection("chatrooms").doc(chatId).collection(chatId).where("timestamp", "==", timekey).get().then((QuerySnapshot) => {
if (!QuerySnapshot.empty) {
const deleteDocs = []
QuerySnapshot.forEach((doc)=>{
console.log(doc.data().value)
deleteDocs.push(doc.ref.delete())
});
Promise.all(deleteDocs).then(() => {
console.log("Docs delete")
}).catch(e => console.log(e))
} else {
// doc.data() will be undefined in this case
console.log("No such document!");
}
});
PS: You don't need to use Template Literals [${} thing] if you just have one variable.
You can directly pass the var as .doc(chatId)

Adding a document and adding a sub-collection to that document Firestore

db.collection("rooms").add({
code: this.state.code,
words: []
}).then(() => {
db.collection("rooms").where("code", "==", this.state.code).get().then((doc) => {
doc.collection("players").add({name: this.state.name, votes: 0}).then(() => {
socket.emit("createGroup", this.state.code);
});
});
});
I am building a React/Express app using client-side Firestore calls and SocketIO. I'm getting the following error in console: "Uncaught (in promise) TypeError: t.collection is not a function". I guess the Firestore document -> {code: this.state.code, words: []} has somehow not yet been created when I reference it in the then function -> db.collection("rooms").where("code", "==", this.state.code). Any suggestions on how I can fix this error while still maintaining the order of the Firestore calls?
When you call get() on a Query object as you are here:
db.collection("rooms").where("code", "==", this.state.code).get()
It's going to return a promise that yields a QuerySnapshot object. That object does not have a method called collection() on it. It contains the results of the query that you will have to deal with.
You're going to have to iterate or otherwise handle the results of that query to move forward. Your code should also be prepared for the case that that query returns no documents. Use the docs array property on the QuerySnapshot to learn about what happened.
db.collection("rooms").where("code", "==", this.state.code).get().then(querySnapshot => {
querySnapshot.docs.forEach(snapshot => {
// handle each document individually, if any
})
});
I suggest also reviewing the documentation on Firestore queries, along with the API documentation I linked above.
db.collection("rooms").add({
code: this.state.code,
words: []
}).then(() => {
db.collection("rooms").where("code", "==", this.state.code).get().then((querySnapshot) => {
querySnapshot.docs.forEach((snapshot) => {
snapshot.ref.collection("players").add({name: this.state.name, votes: 0}).then(() => {
socket.emit("createGroup", this.state.code);
});
});
});
});
This implementation works thanks to help from Doug.

How can I query map object which is the document ID in firebase?

I am trying to fetch all fieldnames inside of payload > (random doc id) objects.
Currently I am fetching other collections with:
async fetchPage() {
const query = firebase
.firestore()
.collection('PAGES')
.where('type', '==', 'page')
try {
const { docs } = await query.get()
this.pageIndex = docs.map((doc) => {
if (doc && doc.exists) {
this.items = doc.data()
}
let { id } = doc
const data = doc.data()
return { id, ...data }
})
console.log('Loaded items', this.items)
} catch (error) {
throw new Error('Something gone wrong!')
}
},
The first question is: What is the best practice to query objects? I read this in firebase docs but didn't lead me to any results trying it out that way.
Second question, since the child object of payload is the actual id of its document, what method must I use to declare that I'm looking for e.g payload > doc id > content: "This is some content"?.
Here are some information that are helpful about how Firestore operates and they may prove helpful to you on how to improve queries in your database.
Here is the Firebase documentation about queries and the Query Client Library.
This is an article that refers to the causes of slow queries.
Regarding your second question you can get a snapshot of the whole document and then you have to iterate through the data.
Let me know if this is helpful to you.

Multiple document gets deleted from firestore collection from the view while deleting one

I am subscribed to a collection using the async pipe, however when I go to delete a document inside the collection, any document below the deleted document also gets removed from the UX and but when i reload the component, i get that document again from firestore.
This is the code i am using to fetch guide collection
getGuides() {
return this.db.collection('guides').snapshotChanges()
.map(data => {
return data.map(a => {
let id = a.payload.doc.id;
let data = a.payload.doc.data();
return { id, ...data };
})
})
}
And this code is to delete the document with it's id
deleteGuide(id) {
return this.db.doc('guides/' + id).delete();
}
Thanks!
gif with problem

Categories

Resources