Firestore get document where subcollection exist - javascript

It this possible to do? After some research, I couldn't find a way to do it.
My "workaround" is to get all subCollection documents first, then retrieve their parent keys and retrieve again. But I believe there is a better way to do it.
let subDocs = await firestoreDb.collectionGroup('sub_collections').get()
let parentDocKeys = {};
subDocs.docs.forEach(async (element) => {
parentDocKeys[element.ref.parent.parent.id] = 1;
});
let result = await firestoreDb.collection('parentCollection').where(firestore.FieldPath.documentId(), 'in', Object.keys(parentDocKeys)).get();
return res.send(result.docs.map(x=>x.data()));

Firestore queries can only filter documents based on data in the document itself. There is no way to check data in any other documents, neither in the same collection, nor in other (sub)collections.
This means that it is not possible to retrieve only documents for which a subcollection exists without changing the data in the parent document. For example, if you update a field (say hasSubcollectionBla) in the parent document each time you add/remove to the subcollection, you can filter on the value of that field.
What you do with this is making the writing of data more complex, so that the read/query becomes easier and more scalable. This is a common trade-off when using NoSQL databases, such as Firestore.

Related

Deleting data in firebase 7

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();
`

How to go through dynamic Firebase Realtime Database?

I am making a web app that accesses a Firebase Real-Time Database. The database will be of a dynamic size as new data is entered.
example:
Each element holds an irrelevant object.
I've hard-coded the size and am for-looping through it (js):
for (let i = 0; i < DB_SIZE; i++) {
let ref = firebase.database().ref(i.toString());
let snapshot = await ref.once('value');
let data = snapshot.val();
}
The data achieved is the object associated with the element.
This works when I know the exact, unchanging size of the database, but when a new object is added as a new element in the database, my loop wouldn't access it, since the database size is now larger.
How can I access the data in this dynamic database using Firebase's syntax? It's possible that try...catch will be involved, but I'm not so sure.
The Firebase DataSnapshot has a built-in forEach method precisely for this purpose. So you can load the entire parent node, and then loop over it client-side with:
const snapshot = await firebase.database().ref().once('value');
snapshot.forEach((child) => {
let data = child.val();
});
By the way, Firebase recommends against using sequential, numeric indexes as the keys. For an explanation why, see Best Practices: Arrays in Firebase.

Retrieve data from multiple documents from Firestore

I tried a lot of times but I am still not able to retrieve data from multiple documents, The below screenshot shows that I have 3 documents in my collection and my question is how to retrieve data from each of them.
I used foreach loop to loop through all the documents but I don't know how to retrieve data from id RoKQBRcuaVfcGPKNswbx or id Y8KbSQHcuxctJCJ1lWYH because it auto retrieve the data of the last id.
I really need your help, please.
Thank you.
The snapshot object contains all the 3 documents in your collection. You must iterate over all and render data to your HTML as explained below.
db.collection("Policies List").get().then((snapshot) => {
const documents = snapshot.docs //array of documents
documents.forEach((doc) => {
const docData = doc.data() //Data of that single document
console.log(docData)
renderToHtml() // Code that creates new HTML elements
})
})
This way you are creating new HTML elements for all the documents in your collection. The renderToHtml() function will contain that .innerHTML code.
Please make sure to see the logs in the console. They'll help understand the structure in a better way.

Firestore JS - incrementing within transactions

I have some code that looks like the following:
export const createTable = async (data) => {
const doc = db.collection("tables").doc();
const ref = db
.collection("tables")
.where("userId", "==", data.userId)
.orderBy("number", "desc").limit(1);
db.runTransaction(async transaction => {
const query = await transaction.get(ref);
let number = 1;
if (!query.empty) {
const snapshot = query.docs[0];
const data = snapshot.data();
const id = snapshot.id;
number = data.number + 1;
}
data = {number, ...data};
transaction.set(doc, data);
});
Basically I have a tables collection and each table has an auto generated number like #1, #2, #3
When creating new tables, I want to fetch the latest table number and create the new table with that number incremented by 1.
I wanted to wrap it in a transaction so that if a table created while running the transaction, it will restart so that I don't end up with duplicate numbers.
However, this errors out on the .get(), and from googling I've read that Firestore can't monitor a whole collection within transactions, but instead it requires a specific doc passed to it. Which I obviously can't do because I need to monitor for new docs created in that collection, not changes in a particular doc.
If so, what's the correct way to implement this?
The Firestore transaction API for client apps requires that you get() each individual document that you want to participate in the transaction. So, if you have a query whose results you want to transact with, you will need to:
Perform the query (outside of the transaction)
Collect document references for each document in the result set
In the transaction, get() them all individually.
You will be limited to 500 documents per transaction.
If you want to dynamically look for new documents to modify, you will probably much better off implementing that on the backend using a Firestore trigger in Cloud Functions to automatically handle each new document as they are created, without requiring any code on the client.
Because you're updating just one document, you probably don't need to use transactions for incrementing values.
You can use Firestore Increment to achieve this.
Here is an example taken from here:
const db = firebase.firestore();
const increment = firebase.firestore.FieldValue.increment(1);
// Document reference
const storyRef = db.collection('stories').doc('hello-world');
// Update read count
storyRef.update({ reads: increment });
This is the easiest way to increment values in Firestore.

More direct method for updating fields in Firebase document without document ID?

The goal is to update a Firebase document.
The document ID is unknown at the time of updating. What is known is a property that acts as unique key on the document (email address in the case below).
Based on the official documentation and this answer, the code below works as a method for updating an array within the document.
This feels clunky, though.
Are there more direct methods for retrieving a reference to a single document and updating its fields?
// Set query.
let query = firebase.firestore().collection('users').where('emailAddress', '==', 'test#test.com');
// Run query.
try {
const querySnapshot = await query.get();
return querySnapshot.docs[0].ref.update({
designs: firebase.firestore.FieldValue.arrayUnion('foobar')
})
} catch(e) {
console.log('Error getting user: ', e);
}
No, what you're doing is the best you can do. If you don't know the ID, you have to query to find it. Firestore has no equivalent of a SQL "update where" command.

Categories