Perform simple queries in Cloud Firestore - how can i filter all through select? - google-cloud-firestore

I need to to filter data through queries from Firestore, but how can I also get all of them(in my case all states in firestore)? What should be useState value in this case? I'm a newbie :) Thank you for your help, I really appreciate it.
//WHAT useState VALUE SHOULD I USE TO GET ALL STATES IN DATABASE?
const (city, setCity) = useState("CA");
const citiesRef = collection(db, "cities");
const q = query(citiesRef, where("state", "==", city));
Tried to search in firestore docs and google.

you need to use getDocs() method provided by firebase as follows
here, q is your query ( const q = query(collection(db, "cities"), where(....));
add following code -
const querySnapshot = await getDocs(q);
querySnapshot.forEach((doc) => {
// doc.data() is never undefined for query doc snapshots
console.log(doc.id, " => ", doc.data())
});
you can refer to this link

As you wanted to use useState, You can pass an empty string ” “ or Null value and use != instead of = operator in the where clause.
And use getDocs() to retrieve all documents as mentioned by #Prathmesh
Here is the complete code:
const (city, setCity) = useState(" ");
const citiesRef = collection(db, "cities");
const q = query(citiesRef, where("state", "!=", city));
const querySnapshot = await getDocs(q);
querySnapshot.forEach((doc) => {
// doc.data() is never undefined for query doc snapshots
console.log(doc.id, " => ", doc.data());
});

Related

Designing many to many model with map

I am new to firestore and am wondering if anyone could tell me whether this solution is viable for a many-to-many relationship. I have a collection of Rosters and collection of Students which are related Many-to-Many. As the information I most frequently need about a student is just their name, would it be viable to have a map of students like {<StudentID> : "Student Name"} stored in rosters, and so if I want to retrieve more detailed information about students in a roster, I retrieve the map's keys and iterate through them to retrieve each student's document individually?
I am basing my solution off of this answer.
I'd greatly appreciate any advice! Thank you
Update to this, it is working fine. Here is my code for the cloud function to update athlete names if anyone in the future needs:
export const onUserUpdate =
functions.firestore.document("users/{user}/athletes/{athlete}").onUpdate(
async (change) => {
const after = change.after.data();
const before = change.before.data();
const bid = change.before.id;
console.log("BID: ");
console.log(bid);
const userId: any = change.before.ref.parent.parent?.id;
console.log(`users/${userId}/rosters`);
if (after.athleteName != before.athleteName) {
console.log("Change name detected");
const snapshot =
await db.collection(
`users/${userId}/rosters`).where(
`athletes.${bid}`, ">=", "").get();
const updatePromises : Array<Promise<any>> = [];
snapshot.forEach((doc) => {
console.log(doc.id);
updatePromises.push(db.collection(`users/${userId}/rosters`)
.doc(doc.id).update(`athletes.${bid}`, after.athleteName)
);
});
await Promise.all(updatePromises);
}
});

flutter/cloud firestore : How to get only one data from doc?

I use cloud firestore with flutter and I successed to get all key/value from document but I don't successed to match only one id from doc
here is my code:
getgift() async {
final firestoreInstance = FirebaseFirestore.instance;
// Get docs from collection reference
QuerySnapshot querySnapshot = await firestoreInstance.collection("parrainage").get();
// Get data from docs and convert map to List
final mydata= querySnapshot.docs.map((doc) => doc.data()).toString();
print("$mydata");
my current output is ({key1: value1}, {key2: value2})
I trie to match only data from key1 for this exemple.
thank you
}
The following code will return a DocumentSnapshot object.
DocumentSnapshot snapshot = await firestoreInstance.collection("parrainage").doc("key1").get();
You can access its value by doing the following:
dynamic x = snapshot.data(); // will return value1
If I understand correctly, you only want to get value1 to be got. If that's so, then simply do this:
final mydata= querySnapshot.docs.firstWhere((element) => element.data().containsKey(key1));
Or, if ya want to get only the data with key as key1 (instead of getting all the keys and values), do this:
QuerySnapshot querySnapshot = await firestoreInstance.collection("parrainage").doc(key1).get();
final mydata= querySnapshot.get(key1);
Cheers

Firebase | Problem with collectionGroup query

I'm trying to use a collectionGroup query to fetch the data from a specified farm, using firebase-functions. Here's my code:
app.get('/api/intervals/:farm_id', async (req, res) => {
const farmId = req.params.farm_id;
try {
const querySnapshot = await db
.collectionGroup('farms')
.where("id", "==", farmId)
.get();
const farmData = [];
querySnapshot.forEach((doc) => {
farmData.push(doc.data());
console.log(doc.id, ' => ', doc.data());
});
return res.status(200).send(farmData);
} catch (error) {
console.log(error);
return res.status(500).send(error);
}
});
There is definitely a farm in the database with the supplied code. For example, if I change the code in try to the below, I get the data as expected:
const farmRef = db
.collection('accounts')
.doc('lz8V32bjQGa9x1oecUu9')
.collection('farms')
.doc(farmId);
let farm = await farmRef.get();
let farmData = farm.data();
return res.status(200).send(farmData);
But I want to use a collectionGroup so I don't have to specify the parent account ID also.
What am I doing wrong here? Thanks in advance!
According to my understanding this is related with the fact that in your working code you are assigning directly from DocumentSnapshot, while in example in of the issue you are iterating over QuerySnapshot returned by get from query.
In documentation we can find that documents in QuerySnapshot are in array property docs.
So I think you should change forEach loop accordingly:
querySnapshot.docs.forEach((doc) => {
farmData.push(doc.data());
console.log(doc.id, ' => ', doc.data());
});
I have worked out that the problem was that my code was looking for a field named id. My query works if I manually add a field called ID as highlighted below:

FieldValue.increment is not a function

I tried for hours to update the users score stored in cloud firestore in my app using cloud functions but I am getting this error and I can't figure out how to fix this problem.
this is my code :
const auth = require('firebase/auth');
const functions = require('firebase-functions');
const nodemailer = require('nodemailer');
const FieldValue = require('firebase-admin').firestore.FieldValue;
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
const db = admin.firestore();
exports.addPoints = functions.firestore
.document(`users/{user}`)
.onCreate(async (snap, context) => {
const invitingFriendId = snap.data().invitingFriendId;
const invitingFriendRef = db.collection('users').doc(invitingFriendId);
return invitingFriendRef.update("points", db.FieldValue.increment(50));
});
It looks like you're trying to use the functions SDK to query Cloud Firestore. That's not going to work at all. The function SDK is just used for declare function triggers. You need to use the Firebase Admin SDK to actually make the query when the function triggers.
Require firebase-admin in the most simple way:
const admin = require('firebase-admin');
Then make the query with it:
admin.firestore().documet("...").update(...);
FieldValue increment can be referenced like this:
admin.firestore.FieldValue.increment()
I am writing for CloudCode too. It is good to understand that firestore variables do not necessarily point to the same thing as they are just names.
A. The firestore here is used to access the Firestore database and set the data. However, this firestore does not contain the FieldValue:
// The Firebase Admin SDK
const admin = require('firebase-admin')
admin.initializeApp()
//const firestore db, comes after initialize app
const firestore = admin.firestore()
B. Instead, FieldValue is contained, not in admin.firestore() which is the firestore above, but by the firestore object here:
const FieldValue = require('firebase-admin').firestore.FieldValue
C. Thus, completing the above, you can now use the two different firestore variables that we have, code B for getting the FieldValue and A for updating the database
// Cloud Functions and setup triggers.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp()
//const firestore, comes after initialize app
const firestore = admin.firestore()
const FieldValue = admin.firestore.FieldValue
exports.createdLikesTrigger = functions.firestore
.document(`likes/{uid}/posts-liked/{postId}`)
.onCreate(async (snap, context) => {
const uid = context.params.uid
const postId = context.params.postId
const likeDocument = snap.data()
const date = likeDocument.when
const authorUid = likeDocument.author
try{
//increment post count
const increment = FieldValue.increment(1);
await firestore.collection('posts').doc(postId).update({likes: increment})
catch(e){
console.log("Error in incrementing likes: ", e)
}
})
I was seeing the same error message, then managed to get this working with Firebase Functions after updating Firebase Functions to the latest version.
npm install firebase-functions#latest firebase-admin#latest --save
npm install -g firebase-tools
https://firebase.google.com/docs/functions/get-started#set-up-node.js-and-the-firebase-cli
I bumped into the same problem when trying to call decrement while updating a document in a firebase function.
Then I saw these two API docs
https://firebase.google.com/docs/reference/admin/node/admin.firestore.FieldValue
https://firebase.google.com/docs/reference/js/firebase.firestore.FieldValue
Unlike firebase.firestore.FieldValue the admin version doesn't have increment/decrement methods. not sure why is that the case.
So instead I'm first reading the value using get() and then subtracting with an update().

Elegant way to dynamically query firestore [duplicate]

I have fetch some data from firestore but in my query I want to add a conditional where clause. I am using async-await for api and not sure how to add a consitional where clause.
Here is my function
export async function getMyPosts (type) {
await api
var myPosts = []
const posts = await api.firestore().collection('posts').where('status', '==', 'published')
.get()
.then(snapshot => {
snapshot.forEach(doc => {
console.log(doc.data())
})
})
.catch(catchError)
}
In my main function I am getting a param called 'type'. Based on the value of that param I want to add another qhere clause to the above query. For example, if type = 'nocomments', then I want to add a where clause .where('commentCount', '==', 0), otherwise if type = 'nocategories', then the where clause will be querying another property like .where('tags', '==', 'none')
I am unable to understand how to add this conditional where clause.
NOTE: in firestore you add multiple conditions by just appending your where clauses like - .where("state", "==", "CA").where("population", ">", 1000000) and so on.
Add the where clause to the query only when needed:
export async function getMyPosts (type) {
await api
var myPosts = []
var query = api.firestore().collection('posts')
if (your_condition_is_true) { // you decide
query = query.where('status', '==', 'published')
}
const questions = await query.get()
.then(snapshot => {
snapshot.forEach(doc => {
console.log(doc.data())
})
})
.catch(catchError)
}
For the frontend Web SDK:
Or you can look at this link for a different method:
Firestore conditional where clause using Modular SDK v9
let showPublishStatus: boolean = true
let conditionalConstraint: QueryConstraint = showPublishStatus
? where("status", "==", "published")
: where("status", "!=", "published")
let queryWebSDK = query(collection(db, "Collection"), conditionalConstraint)