Firestore sub collection delete oldest in document - javascript

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()
}

Related

How do I check if collection exist in firestore (not document) in JS

Hoi, I would like to check, using React javascript, if a collection in the Firestore already exists, no matter if it's empty or not. I tried:
if (collection(db, ref)) // is always true somehow
Any ideas? Thanks!
You would need to try to fetch from the collection and see if anything is returned:
const snap = await query(collection(db, ref), limit(1));
if (snap.empty) {
// no docs in collection
}
There is no function available in the SDK that can help you can check if a particular collection exists. A collection will start to exist only if it contains at least one document. If a collection doesn't contain any documents, then that collection doesn't exist at all. So that being said, it makes sense to check whether a collection contains or not documents. In code, it should look as simple as:
const snapshot = await query(collection(db, yourRef), limit(1));
if (snapshot.empty) {
//The collection doesn't exist.
}
One thing to mention is that I have used a call to limit(1) because if the collection contains documents, then we limit the results so we can pay only one document read. However, if the collection doesn't exist, there is still one document read that has to be paid. So if the above query yields no resul## Heading ##t, according to the official documentation regarding Firestore pricing, it said that:
Minimum charge for queries
There is a minimum charge of one document read for each query that you perform, even if the query returns no results.
You have to fetch the collection out of the database and check if it has more than 0 documents. Even, if the collection doesn't exist, it will return 0.
const db = firebase.firestore();
db.collection("YOUR COLLECTION NAME").get().then((res) =>{
if(res.size==0){
//Collection does not exist
}else{
//Collection does exist
}

How to get data from document in a parent collection based on a query in a subcollection

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;

Conditinal database record delete firebase

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?

Finding a specific field in firestore with an id

I know this is a very basic question, but I am new to reactjs and firebase. After two days I am giving up on searching for an answer myself.
I have a firestore database 'MusicList' containing several documents. Within these documents the field 'seperatedStrings' holds (you'll probably will be guessing it) artists and titles of songs.
image of the firestore database
How do I retrive the value a single field (in this example 'seperatedString') using the ID (in this example '5ajnHZ8YDaiYvTAvJ1ec'?
Whenever I am querying for this:
firestore().doc("MusicList/" + "5ajnHZ8YDaiYvTAvJ1ec").seperatedString
the console claims that it is "undefined" (That is a lie!), I'd expect 'Phil Upchurch Blackgold'
Thanks in advance.
You are not using Firebase queries correctly. If you want to fetch a document from a collection, you would do so like this:
firebase
.firestore()
.collection('MusicList')
.doc('5ajnHZ8YDaiYvTAvJ1ec')
.get()
.then(doc => {
if (doc && doc.exists) {
const { separatedString } = doc.data();
//use separatedString
}
});
Check out Firestore - Get A Document for more information.
Also, it would probably be better to structure your documents differently. You could have an artist and track field, and use doc.data().artist and doc.data().track respectively.

Saving a field from firestore that is an array

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

Categories

Resources