I want to clean some records of a firestore database. I have a function that receives the records I would like to keep, I check in all the records if id is not in the docsToKeep:firebase documents argument.
I use a foreach for all the records, and I user filter to find the matching id as shown in the working snippet below:
async function checkForNotifClean(docsToKeep:firebase.firestore.QuerySnapshot<firebase.firestore.DocumentData>) {
const db = firebase.firestore();
const notifCollection = db.collection('notifications')
const allData = await notifCollection.get();
allData.docs.forEach(doc => {
const filtered = docsToKeep.docs.filter(entry => entry.id === doc.id);
const needsErase = filtered.length === 0;
if (needsErase) {
const id = doc.id;
notifCollection.doc(id).delete();
}
})
}
Is there a cleaner way to erase all the documents that are not in docsToKeep ? Would be kind of function that get all the objects that are not in both arrays and delete those. I would be happy on improvements on the javascript side to filter out the records to delete, and in the firebase side, improvements regarding the chance of deleting some set of records at once instead of looping through all and deleting each.
To delete (or write to) a document in Firestore you need to know the complete path to that document, including its document ID. If you don't have the IDs of the documents to delete, then your only option is to determine those IDs as you're doing now.
It does lead to the question how docsToKeep is populated though. My guess it that the user already selects some documents from a full list. If that's the case, might you be able to pass the inverted list: docsToDelete?
Related
Hey guys I try to get data from a document which has a Field value Name and a subcollection named kurzwaffensub but for my project I need to do a collectionGroup query and after that I need the Name value of each document which matches the query from the subcollection.
So let me explain.
First I need to do a collectionGroup query of the documents from the subcollection based on their two parameter kurzHersteller and kurzModell which I marked in green at the picture.
After that I get all Documents of every Subcollection which match the query.
And as you can see the blue document uid is the same uid as in the fieldvalue of every document of the subcollection.
And my goal is to get the red marked fieldvalue of the documents of the main collection after the group query of the subcollection.
But I only want to receive the Names of the documents which match the requirments of the query .
So in this Case i need the Name Felix Sturms because he has a document in his subcollection marked in yellow
which match the Search for kurzHersteller : Andere and kurzKaliber : Andere
I dont know if this is possible or if I need to structure my data in another way. Im a beginner with firebase firestore so perhabs you can help me.
const [test, setTest] = useState([]);
const HEuKA = query(kurzRef,where("kurzHersteller", "==", `${kurzHersteller}` ), where('kurzKaliber' , '==', `${kurzKaliber}`));
const handleClick = async () => {
...blablabla
...
} else if (kurzHersteller && kurzKaliber) {
const modell = await getDocs(HeuKa);
modell.forEach((doc) => {
// doc.data() is never undefined for query doc snapshots
setTest(doc.id, " => ", doc.data());
});
} else { alert('Bitte etwas eingeben')}
}
So thats the first operation after I receive the array of the documents of the subcollection which match the query , i need another operation to get the corresponding documents from the parent collection which contain the information about the Name of the users which have a document in the subcollection which match the values kurzHersteller: Andere and kurzModell: Andere of this example.
Once you get the QuerySnapshot from your collection group query, you can loop over every document and then access the parent document using .parent property present on the DocumentReference of each document. Try running the following code after your first query:
const modell = await getDocs(HeuKa);
const data = [];
for (const doc of modell.docs) {
const parentDoc = await getDoc(doc.ref.parent.parent);
const { Name } = parentDoc.data();
data.push({
...doc.data(),
Name,
});
}
Firestore reads/queries return documents from a single collection, or with collection group queries from all collections with the same name. There is no way in Firestore to include data from the parent document in the same read/query.
The two options you have are:
Read the parent document for any result you get from the subcollection.
Duplicate the necessary information from the parent document in each document in the subcollection.
While #1 is the most common option for people who are new to Firestore (and NoSQL databases in general), as you get more experienced with Firestore you'll often find yourself using #2 more often too.
I think a more robust way, where you don't depend on the structure, is to get the document from 'uid' field you have on each document you get back from the query'. Even better would be to change this field to type "reference", in which case you can just do (assuming you create a field called customerReference as a replacement for uid):
modell.forEach((doc) => {
const customerDoc = await doc.data().customerReference.get();
const name = customerDoc.data().Name;
So I'm a newbie in using firebase real time database and I can't delete products key child with id specified.
I've tried this approach but it didn't yield any success:
removeProductById = async (id, user) => {
const userProductRef = db.ref(`products/product`);
try{
var query = userProductRef.orderByChild('id').equalTo(id);
query.remove()
})
}catch(error){
console.log(`The error has occured ${error.message}`)
}
}
So I wanna know how can one delete any tipe of key by whatever value they specify. Thank you in advance, you have always helped me guys.
There are two problems here:
Your query doesn't match the nodes you want delete.
Firebase doesn't support delete-queries.
Your query doesn't match the nodes you want delete
Your query starts at a node products/product, which doesn't exist in your database, and then orders/filters the id property of each child node.
What you want instead is to start at the products node, and then order/filter on its product/id property of each child node:
In code:
const userProductRef = db.ref(`products`);
var query = userProductRef.orderByChild('product/id').equalTo(id);
Don't forget that you'll need to define an index for product/id for this on the products level in your rules.
Firebase doesn't support delete-queries
You can't simply pass the query and delete instruction to Firebase. To write a node in the database, you'll need to know the entire path to that node.
So you'll need to:
Execute the a query.
Loop over the results in your application code.
Delete each matching node individually or in a multi-path update.
With the query above, that'd be:
query.once("value").then((snapshot) => {
snapshot.forEach((child) => {
child.ref.remove();
});
})
Or with a multi-path/batch update:
query.once("value").then((snapshot) => {
let updates = {};
snapshot.forEach((child) => {
updates[child.key] = null;
});
ref.update(updates);
})
I've been struggling with figuring out how to delete documents from a sub collection, keep only the latest 5 documents.
I firstly try and get a list of documents in the sub collection, ordered by 'updated' date timestamp. This however returns null
let updates = await firestore
.collection('spots')
.doc(spot.id)
.collection('spotupdates')
.orderBy('updated','desc');
I then try and delete the oldest from the list, to ensure only 5 remain
var cntr = 0;
while(updates.docs.length > 5){
await firestore
.collection('spots')
.doc(spot.id)
.collection('spotupdates')
.doc(updates[cntr].id)
.delete();
cntr++;
}
cntr = null;
Please help - really stuck
According to Firebase Documentation for deleting data from your database:
To delete an entire collection or subcollection in Cloud Firestore,
retrieve all the documents within the collection or subcollection and
delete them. If you have larger collections, you may want to delete
the documents in smaller batches to avoid out-of-memory errors. Repeat
the process until you've deleted the entire collection or
subcollection.
You may find a simplified code snippet to delete collections and subcollections in this link.
Also you will find more information and detailed examples about deleting fields, documents and collections in Firestore in this link.
Let me know if this was helpful.
I did something similar on my app but based on your data structure
First, get all the documents in the collection
const updates = await firestore
.collection('spots')
.doc(spot.id)
.collection('spotupdates')
.get()
Map the document data to return an array
const updatesArray = updates.docs.map(doc => doc.data())
Do logic then delete
if (updatesArray.length > 5){
const sorted = updatesArray.sort((a,b) => b.created_at - a.created_at)
const oldest = sorted.pop()
await firestore
.collection('spots')
.doc(spot.id)
.collection('spotupdates').doc(oldest.id).delete()
}
I am currently working on a mobile app on React and I am having trouble understanding how to save a field from fire store that is an array.
Since I can't post images my database structure is all strings such as username, first name, etc but I have a field called follow list that is an array.
What I want to do is save the usernames from the following list into an array to later search fire store for the username's in the array, this is basically what I want to do so I can render my app's social Feed. I do know that I can probably create another subcollection and write something familiar to what I did to search for users but that was a QuerySnapShot which was overall documents not a specific one and I also know firebase creates an ID for arrays and it increases as the array gets bigger.
I do not want to end up making two more subcollections one for followers and following which I think not ideal right? My current approach is this
export const fetchUserFollowing = async (username) => {
const ref = firebase.firestore().collection('users').doc(username)
let results = []
ref
.get()
.then( doc => {
let data = doc.data()
results = data
})
.catch((err) => {
return 'an error has occurred ', err
})
}
From what I understand is that a DocumentSnapShot .get() function returns an object but what I want is to store follow list into results and then return that but I am not sure how to manipulate the object return to just give me follow List which is an array
https://rnfirebase.io/docs/v5.x.x/firestore/reference/DocumentSnapshot
link to docs
I am fetching data from firestore and displaying those data's in a list.But the response which i am getting from firestore contains the document id separately and values separately. At the time of fetching itself i am combining it in a array. I would like to know whether it is the correct way of doing or is there any way we can do it better to combine the document id and values together.
Steps which i have done for combining:
db.getEmployees().then((snapshot) => {
let employee = [];
snapshot.docs.forEach((doc) => {
let user = doc.data();
user.id = doc.id;
employee.push(user);
});
dispatch(employeeUpdateSuccess(employee));
According to the documentation for a DocumentSnapshot, there is no way to get the data and the id in a combined way (i.e. with only one method or via one property). In other words, you will always have to use the two following lines of code:
... = doc.data();
... = doc.id;