How can I get specific document data from firestore querysnapshot? - firebase

I got a querysnapshot in a function.
And want to bring the whole querysnapshot to another function (functionTwo).
In functionTwo, I want to get a specific document in the querysnapshot WITHOUT forEach. The specific doc can be changed by different cases.
ref_serial_setting.get()
.then(querysnapshot => {
return functionTwo(querysnapshot)
})
.catch(err => {
console.log('Error getting documents', err)
})
let functionTwo = (querysnapshot) => {
// getting value
const dataKey_1 = "dataKey_1"
// Tried 1
const value = querysnapshot.doc(dataKey_1).data()
// Tried 2
const value = querysnapshot.document(dataKey_1).data()
// Tried 3 (Put 'data_name': dataKey_1 in that doc)
const value = querysnapshot.where('data_name', '==', dataKey_1).data()
}
The result are all these trying are not a function.
How can I get specific document data from querysnapshot??
or
Is there any easy method to change the querysnapshot to JSON?

You can get an array of the document snapshots by using the docs property of a QuerySnapshot. After that you'll have to loop through getting the data of the doc snapshots looking for your doc.
const docSnapshots = querysnapshot.docs;
for (var i in docSnapshots) {
const doc = docSnapshots[i].data();
// Check for your document data here and break when you find it
}
Or if you don't actually need the full QuerySnapshot, you can apply the filter using the where function before calling get on the query object:
const dataKey_1 = "dataKey_1";
const initialQuery = ref_serial_setting;
const filteredQuery = initialQuery.where('data_name', '==', dataKey_1);
filteredQuery.get()
.then(querySnapshot => {
// If your data is unique in that document collection, you should
// get a query snapshot containing only 1 document snapshot here
})
.catch(error => {
// Catch errors
});

Theres an easy way to do this, each QuerySnapshot has a property docs which returns an array of QueryDocumentSnapshots. See QuerySnapshot documentation.
let citiesRef = db.collection('cities');
let query = citiesRef.where('capital', '==', true).get().then(snapshot => {
snapshot.docs[0]; // => returns first document
});

let citiesRef = db.collection('cities');
let query = citiesRef.where('capital', '==', true).get()
.then(snapshot => {
if (snapshot.empty) {
console.log('No matching documents.');
return;
}
snapshot.forEach(doc => {
console.log(doc.id, '=>', doc.data());
});
})
.catch(err => {
console.log('Error getting documents', err);
});
from https://firebase.google.com/docs/firestore/query-data/get-data

you can use this code :
const querySnapshot = await getDocs(collection(db, "collectionNaame"));
const docSnapshots = querySnapshot.docs;
for (var i in docSnapshots) {
console.log(i)
const doc = docSnapshots[i].data();
console.log(doc)

Just do
db.doc(<<ref>>).get()
this returns a promise
[here ]: https://firebase.google.com/docs/firestore/query-data/get-data#get_a_document is the link to the docs

Related

How to filter in sub collection's documents (firebase)?

My problem is that I use wrong query to get the date.
const SaveDateBase = async ( e) => {
e.preventDefault()
await setDoc(doc(db, "Users", "Pompy", "Pompy", user.uid), {
displayName: user.displayName,
uid: user?.uid,
modulyPV}).then(()=>{
console.log("moduly", modulyPV)
})
};
useEffect(() => {
const getUsers = async (users) => {
const URC = query(collection(db, "Users").document("Pompy").collection("Pompy"), where("uid", "==", user?.uid));
const data = await getDocs(URC)
setModulyPV(data.docs.map((doc) => ({...doc.data(), id: doc.id})))
}
getUsers();
},[])
The date are saved in date base, and I can successfully update/delete them, but I do something wrong to fetch (read?) them.
I guess is problem with the code.
You can get the data in diff ways, first "Pompy" seems to be your document where you are storing a nested collection then you document "Pompy" So for retrieve that specific document should be something like:
let snapshot = await db
.collection('Users')
.doc('Pompy')
.collection('Pompy')
.get()
snapshot.forEach(doc =>{
console.log('data:', doc.data())
})
Then to query into the nested collection would be something like querying the nested collections.
https://cloud.google.com/firestore/docs/samples/firestore-data-get-sub-collections?hl=es-419#firestore_data_get_sub_collections-nodejs
You can also use collection groups.
https://firebase.google.com/docs/firestore/query-data/queries#collection-group-query
const pompys = query(collectionGroup(db, 'Pompy'), where("uid", "==", user?.uid));

Firestore Collection Doesn't retrieve expected output

I have a react native function to to get all collection documents as follows
export const fetchAuctionItems = () => {
return firestore().collection('items').get();
};
When I'm accessing above function response not getting any documents instead that I'm getting following
Can anyone one help me to solve my problem, Thank you
collection.get() returns a a QuerySnapshot and this is the data you are seeing. You need to request the data from the QuerySnapshot, like so for example.
export const fetchAuctionItems = () => {
return firestore().collection('items')
.get()
.then(querySnapshot => querySnapshot
.docs
.map(d => ({
id: d.id,
...d.data(),
});
};
Read more about QuerySnapshot here

Firestore transaction failing inside forEach loop

I am trying to update several Firestore documents, based on the result of a third-party service inside a transaction. Problem is, I am getting the following error:
Error: Cannot modify a WriteBatch that has been committed.
Here is my code:
export default async function debitDueTransactions(context: any) {
const now = new Date().getTime();
return db.runTransaction(async (transaction: FirebaseFirestore.Transaction) => {
const chargesToCaptureRef = db.collection(`charges_to_capture`)
.where('dateToCapture', '>=', now)
.where('dateToCapture', '<=', (now + 86400000))
.where('captureResult', '==', null);
return transaction.get(chargesToCaptureRef).then((chargeToCaptureQuerySnap: FirebaseFirestore.QuerySnapshot) => {
chargeToCaptureQuerySnap.forEach(async (doc: FirebaseFirestore.QueryDocumentSnapshot) => {
const chargeToCapture = <ChargeToCapture>doc.data();
chargeToCapture.id = doc.id;
let errorKey = null;
// Calling third party service here, waiting response
const captureResult = await captureCharge(chargeToCapture.chargeId).catch((error: any) => {
errorKey = error.code ? error.code : 'unknown_error';
});
transaction.update(doc.ref, { captureResult: captureResult, errorKey: errorKey });
});
return new Promise((resolve) => { resolve(); });
})
});
}
Can't get what I am doing wrong, any idea ?
As you can see from the API documentation, transaction.get() only accepts a DocumentReference type object. You're passing it a Query object. A Firestore transaction isn't capable of transacting on a Query. If you want to transact on all the documents returned from a Query, you should perform the query before the transaction, then use transaction.get() on each DocumentReference individually.

Delete Firestore documents based on where condtiion [duplicate]

var jobskill_ref = db.collection('job_skills').where('job_id','==',post.job_id);
jobskill_ref.delete();
Error thrown
jobskill_ref.delete is not a function
You can only delete a document once you have a DocumentReference to it. To get that you must first execute the query, then loop over the QuerySnapshot and finally delete each DocumentSnapshot based on its ref.
var jobskill_query = db.collection('job_skills').where('job_id','==',post.job_id);
jobskill_query.get().then(function(querySnapshot) {
querySnapshot.forEach(function(doc) {
doc.ref.delete();
});
});
I use batched writes for this. For example:
var jobskill_ref = db.collection('job_skills').where('job_id','==',post.job_id);
let batch = firestore.batch();
jobskill_ref
.get()
.then(snapshot => {
snapshot.docs.forEach(doc => {
batch.delete(doc.ref);
});
return batch.commit();
})
ES6 async/await:
const jobskills = await store
.collection('job_skills')
.where('job_id', '==', post.job_id)
.get();
const batch = store.batch();
jobskills.forEach(doc => {
batch.delete(doc.ref);
});
await batch.commit();
//The following code will find and delete the document from firestore
const doc = await this.noteRef.where('userId', '==', userId).get();
doc.forEach(element => {
element.ref.delete();
console.log(`deleted: ${element.id}`);
});
the key part of Frank's answer that fixed my issues was the .ref in doc.ref.delete()
I originally only had doc.delete() which gave a "not a function" error. now my code looks like this and works perfectly:
let fs = firebase.firestore();
let collectionRef = fs.collection(<your collection here>);
collectionRef.where("name", "==", name)
.get()
.then(querySnapshot => {
querySnapshot.forEach((doc) => {
doc.ref.delete().then(() => {
console.log("Document successfully deleted!");
}).catch(function(error) {
console.error("Error removing document: ", error);
});
});
})
.catch(function(error) {
console.log("Error getting documents: ", error);
});
or try this, but you must have the id beforehand
export const deleteDocument = (id) => {
return (dispatch) => {
firebase.firestore()
.collection("contracts")
.doc(id)
.delete()
}
}
You can now do this:
db.collection("cities").doc("DC").delete().then(function() {
console.log("Document successfully deleted!");
}).catch(function(error) {
console.error("Error removing document: ", error);
});
And of course, you can use await/async:
exports.delete = functions.https.onRequest(async (req, res) => {
try {
var jobskill_ref = db.collection('job_skills').where('job_id','==',post.job_id).get();
jobskill_ref.forEach((doc) => {
doc.ref.delete();
});
} catch (error) {
return res.json({
status: 'error', msg: 'Error while deleting', data: error,
});
}
});
I have no idea why you have to get() them and loop on them, then delete() them, while you can prepare one query with where to delete in one step like any SQL statement, but Google decided to do it like that. so, for now, this is the only option.
If you're using Cloud Firestore on the Client side, you can use a Unique key generator package/module like uuid to generate an ID. Then you set the ID of the document to the ID generated from uuid and store a reference to the ID on the object you're storing in Firestore.
For example:
If you wanted to save a person object to Firestore, first, you'll use uuid to generate an ID for the person, before saving like below.
const uuid = require('uuid')
const person = { name: "Adebola Adeniran", age: 19}
const id = uuid() //generates a unique random ID of type string
const personObjWithId = {person, id}
export const sendToFireStore = async (person) => {
await db.collection("people").doc(id).set(personObjWithId);
};
// To delete, get the ID you've stored with the object and call // the following firestore query
export const deleteFromFireStore = async (id) => {
await db.collection("people").doc(id).delete();
};
Hope this helps anyone using firestore on the Client side.
The way I resolved this is by giving each document a uniqueID, querying on that field, getting the documentID of the returned document, and using that in the delete. Like so:
(Swift)
func rejectFriendRequest(request: Request) {
DispatchQueue.global().async {
self.db.collection("requests")
.whereField("uniqueID", isEqualTo: request.uniqueID)
.getDocuments { querySnapshot, error in
if let e = error {
print("There was an error fetching that document: \(e)")
} else {
self.db.collection("requests")
.document(querySnapshot!.documents.first!.documentID)
.delete() { err in
if let e = err {
print("There was an error deleting that document: \(e)")
} else {
print("Document successfully deleted!")
}
}
}
}
}
}
The code could be cleaned up a bit, but this is the solution I came up with. Hope it can help someone in the future!
const firestoreCollection = db.collection('job_skills')
var docIds = (await firestoreCollection.where("folderId", "==", folderId).get()).docs.map((doc => doc.id))
// for single result
await firestoreCollection.doc(docIds[0]).delete()
// for multiple result
await Promise.all(
docIds.map(
async(docId) => await firestoreCollection.doc(docId).delete()
)
)
delete(seccion: string, subseccion: string)
{
const deletlist = this.db.collection('seccionesclass', ref => ref.where('seccion', '==', seccion).where('subseccion', '==' , subseccion))
deletlist.get().subscribe(delitems => delitems.forEach( doc=> doc.ref.delete()));
alert('record erased');
}
The code for Kotlin, including failure listeners (both for the query and for the delete of each document):
fun deleteJobs(jobId: String) {
db.collection("jobs").whereEqualTo("job_id", jobId).get()
.addOnSuccessListener { documentSnapshots ->
for (documentSnapshot in documentSnapshots)
documentSnapshot.reference.delete().addOnFailureListener { e ->
Log.e(TAG, "deleteJobs: failed to delete document ${documentSnapshot.reference.id}", e)
}
}.addOnFailureListener { e ->
Log.e(TAG, "deleteJobs: query failed", e)
}
}

Return document collection as json from firestore

How can I return a collection of documents from firestore database.
For example, I have a collection named countries in cloud firestore, and I want to fetch all the country names and ids as json , like this
[
{
"countryId" : 1,
"countryName" : "Any"
},
{
"countryId" : 2,
"countryName" : "India"
}
]
Now I am doing a foreach on the snapshot. Is that the only way to convert a collection to json?
What you're doing is correct. You have to iterate each document in the collection/query, and generate the JSON yourself from there. There is no single operation for converting a collection to some other format in its entirety.
There is a way to get the collection without loop.
const companies = async (req, res) =>{
const {id} = req.query;
db.collection("users")
.where("role", "==", "vendor")
.get()
.then((querySnapshot) => {
var docs = querySnapshot.docs.map(doc => doc.data());
res.status(200).json(docs);
});
}
Try this approach
const db = admin.firestore();
......
......
async function getCollection (req, res){
try{
let result = await db.collection('collection_name').get(); //TODO: add query if needed
let response = [];
result.forEach(doc => {
response.push(doc.data());
});
return res.send( { "collection" : response} );
}catch(err){
res.status(500).send(err);
}
}

Resources