Firestore query returns nothing - javascript

Here is the structure of the firestore database
ingredients->(doc name)-> ingredientName: "Apple"
I am trying to figure out the document name of the document with Apple in it but I keep running into an issue where nothing is returned.
async function getIngredientID(){
const q = query(collection(fsdb, 'ingredients'), where('ingredientName', '==', 'Apple'));
const querySnapshot = await getDocs(q);
querySnapshot.forEach((doc) => {
console.log(doc.id, " => ", doc.data());
});
}
there is nothing that comes out on the console. At one point I console logged the value of q and there was no document there. All of the StackOverflow answers have to do with Web version 8 but I am working with Web version 9.

I imagine you must have the imports, make sure you have them all correctly. Now import >>fsdb<< make sure to start cloud firestore and get a reference to the service, check that the where method is correct as well as the collection, i don't know what information it has when initializing firebase, it would be nice if you could send more information, if this information does not help you
import { collection, getDocs, query, where } from "firebase/firestore";
import { fsdb } from '../fb';
async function getIngredientID() {
try {
const q = query(
collection(fsdb, "ingredients"),
where("ingredientName", "==", "Apple")
);
const { docs } = await getDocs(q);
const data = docs.map((doc) => ({
id: doc.id,
...doc.data(),
}));
} catch (error) {
console.log(error);
}
}

Related

array.prototype..forEach function skipped with values in variable

I have a problem, i have a Firebase Firestore Database connected to my React.JS Project, where users can enroll to courses. Now if i'm trying to load the users collection from the DB it returns 1 entry.
const fetchAthletes = async () => {
debugger
try {
const athletes: Array<any> = [];
const athleteRef = collection(db, COLLECTION_NAME_ATHLETE);
const getAthleteQuery = query(athleteRef, where('user', '==', userAuthToken.accessToken));
const querySnapshot = await getDocs(getAthleteQuery)
if (querySnapshot.docs) {
//this for each gets skipped, even when querySnapshot.doc has values in it
querySnapshot.forEach((doc) => {
athletes.push({
id: doc.id,
...doc.data()
});
setAthletes(athletes as Array<Athlete>);
})
}
} catch (error: unknown) {
enqueueSnackbar((error as string), { variant: 'error', autoHideDuration: 3000 })
}
}
But when i want to loop over it via array.prototype.map it always skips it.
I debbuged through the funtion and found out that docs from Firestore is set with values tbat i wanna recieve.
Data returned by Firestore
I have no clue why it doesn't work. Any idea or help is appreciated
Rather than attempt to individually set each doc into state, build up your array and set the entire thing into state
const querySnapshot = await getDocs(getAthleteQuery);
setAthletes(querySnapshot.docs.map((doc) => ({
id: doc.id,
...doc.data(),
}));

How to get a Subcollection inside a Collection in Firestore Web Version 9 (Modular)?

I was using the chaining mode of the Firestore Web 8, but I'm in the way of updated it to Module 9 and have been a hard time trying to figure out how to get all the content of my subcollection (collection inside my collection).
My older function is like this and works fine:
function getInfo(doc_name) {
let infoDB = db
.collection("collection_name")
.doc(doc_name)
.collection("subcollection_name")
.get();
return alunoHistorico;
}
so with the module way I tried this code
// Initialize Firebase
const app = initializeApp(firebaseConfig);
const db = getFirestore(app);
const docRef = doc(db, "collection_name", "doc_name");
const docSnap = await getDoc(docRef);
if (docSnap.exists()) {
console.log("Document data:", docSnap.data());
} else {
// doc.data() will be undefined in this case
console.log("No such document!");
}
but the function doc() expects a even arguments (not counting the db argument) so if I try to use with 3 arguments like this, I get a error:
const docRef = doc(db, "collection_name", "doc_name", "subcollection_name");
to it work I have to pass the exactly document that is inside the subcollection
const docRef = doc(db, "collection_name", "doc_name", "subcollection_name", "sub_doc");
but it doesn't work for me because I have a list os docs inside the subcollection, that I want o retrieve.
So how can I get all my docs inside my subcollection?
Thanks to anyone who take the time.
You need to use collection() to get a CollectionReference instead of doc() which returns a DocumentReference:
const subColRef = collection(db, "collection_name", "doc_name", "subcollection_name");
// odd number of path segments to get a CollectionReference
// equivalent to:
// .collection("collection_name/doc_name/subcollection_name") in v8
// use getDocs() instead of getDoc() to fetch the collection
const qSnap = getDocs(subColRef)
console.log(qSnap.docs.map(d => ({id: d.id, ...d.data()})))
I wrote a detailed answer on difference between doc() and collection() (in V8 and V9) here:
Firestore: What's the pattern for adding new data in Web v9?
If someone want to get realtime updates of docs inside sub collection using onSnapshot in Modular Firebase V9, you can achieve this like:
import { db } from "./firebase";
import { onSnapshot, collection } from "#firebase/firestore";
let collectionRef = collection(db, "main_collection_id", "doc_id", "sub_collection_id");
onSnapshot(collectionRef, (querySnapshot) => {
querySnapshot.forEach((doc) => {
console.log("Id: ", doc.id, "Data: ", doc.data());
});
});

Firebase Firestore is not creating a doc - any idea how to debug?

I've been struggling with a weird error. Can't create a doc in firebase. There are no security rules to speak of, just:
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write;
}
}
}
Firestore is initialised the normal way and is active:
import { Firebase } from "../db";
let firebase = Firebase();
let firestore = firebase.firestore();
But nothing happens after this is run other than printing "here1", the other consoles aren't doing anything and the userid doc is not being created and no collection and doc under it.
export const addEnquiry = async (data) => {
let user = await firebase.auth().currentUser;
data.uid = user.uid;
console.log("here1");
const enquiry = await firestore.collection("users").doc(data.uid).collection("enquiries").doc();
return await enquiry
.set(data)
.then((doc) => {
console.log("here2");
return true;
})
.catch((err) => {
console.log("here3");
console.log(err);
return false;
});
};
The above doesn't print anything other than "here1" and gets stuck on the setting of the doc. The doc isn't created in Firestore either.
Any idea what might be wrong and how to debug it? Wasted a good 4 hours on trying to figure it out and worried if Firestore is so buggy that it's unsafe to use it in production.
First of all, I assure you Firebase is not buggy at all, we have it running on several production applications and they're running fantastic.
Second, I think your issue here is that you're passing a function as the second argument in the set() method, which is nowhere that I can find in the API reference. Instead, it returns a promise. Your code should look like this:
firebase.firestore()
.collection("users")
.doc(uid)
.set({ uid: uid })
.then((doc) => { console.log(doc.id) })
.catch((err) => { console.log(err) })
Cheers.
Here is an example which will work for you:
file test.mjs
import { Firestore } from '#google-cloud/firestore';
const firestore = new Firestore()
export default (uid) => firestore.collection("users")
.doc(uid)
.set({ uid })
.then(() => console.log('success')) // documentReference.set() returns: Promise < void >
.catch(err => console.error(err))
It's super weird, but what solved the issue for me is adding an unnecessary doc.get() like so:
export const addEnquiry = async (data) => {
let user = await firebase.auth().currentUser;
data.uid = user.uid;
console.log("here1");
const enquiry = await firestore.collection("users").doc(data.uid).collection("enquiries").doc();
const x = await firestore.collection("users").doc(data.uid).get();
// ^^^ added the above line I don't actually need, but somehow it
// establishes a connection to firebase or something which allows the
// promise below to resolve, rather than just hang!
// Doesn't resolve without it for whatever reason!
return await enquiry
.set(data)
.then((doc) => {
console.log("here2");
return true;
})
.catch((err) => {
console.log("here3");
console.log(err);
return false;
});
};
When removing the line, the function hangs again. So have to keep it in for now!
A bit worrying that we have to use such workaround hacks to make a simple write to the firestore, to work, Firebase!
Nonetheless, hope it helps someone facing this undebuggable problem.

Query firestore database for document id

I want to query a firestore database for document id. Currently I have the following code:
db.collection('books').where('id', '==', 'fK3ddutEpD2qQqRMXNW5').get()
I don't get a result. But when I query for a different field it works:
db.collection('books').where('genre', '==', 'biography').get()
How is the name of the document id called?
I am a bit late, but there is actually a way to do this
db.collection('books').where(firebase.firestore.FieldPath.documentId(), '==', 'fK3ddutEpD2qQqRMXNW5').get()
This might be useful when you're dealing with firebase security rules and only want to query for the records you're allowed to access.
Try this:
db.collection('books').doc('fK3ddutEpD2qQqRMXNW5').get()
(The first query is looking for an explicit user-set field called 'id', which probably isn't what you want.)
You can use the __name__ key word to use your document ID in a query.
Instead of this db.collection('books').doc('fK3ddutEpD2qQqRMXNW5').get() you can write
db.collection('books').where('__name__', '==' ,'fK3ddutEpD2qQqRMXNW5').get().
In this case you should get an array of length 1 back.
The firebase docs mention this feature in the rules documentation. https://firebase.google.com/docs/reference/rules/rules.firestore.Resource
June, 2021
The new v9 modular sdk is tree-shakeable and results in smaller compiled apps. It is recommended for all new Firestore apps.
import { doc, getDoc } from "firebase/firestore";
const snap = await getDoc(doc(db, 'books', 'fK3ddutEpD2qQqRMXNW5'))
if (snap.exists()) {
console.log(snap.data())
}
else {
console.log("No such document")
}
This is based on the example from the firestore docs
import { doc, getDoc } from "firebase/firestore";
const docRef = doc(db, "cities", "SF");
const docSnap = await getDoc(docRef);
if (docSnap.exists()) {
console.log("Document data:", docSnap.data());
}
else {
// doc.data() will be undefined in this case
console.log("No such document!");
}
You could make this into a helper function
async function getDocument (coll, id) {
const snap = await getDoc(doc(db, coll, id))
if (snap.exists())
return snap.data()
else
return Promise.reject(Error(`No such document: ${coll}.${id}`))
}
getDocument("books", "fK3ddutEpD2qQqRMXNW5")
You can get a document by its id following this pattern:
firebase
.firestore()
.collection("Your collection")
.doc("documentId")
.get()
.then((docRef) => { console.log(docRef.data()) })
.catch((error) => { })
While everyone is telling to use .get(), which is totally reasonable but it's not always the case.
Maybe you want to filter data based on id (using a where query for example).
This is how you do it in Firebase v9 modular SDK:
import {collection, documentId} from 'firebase/firestore'
const booksRef = collection('books')
const q = query(booksRef, where(documentId(), '==', 'fK3ddutEpD2qQqRMXNW5'))
Currently only working way for Cloud Functions if you really need to use this way:
// Import firebase-admin
import * as admin from "firebase-admin";
// Use FieldPath.documentId()
admin.firestore.FieldPath.documentId()
const targetUser = await db.collection("users").where(admin.firestore.FieldPath.documentId() "==", "givenId").get();
Simpler way of this is directly using ID value thru path as there is only one document with given document ID:
const targetUser = await db.doc("users/"+ "givenId").get();
However, you may really need to use it if you are matching given IDs array to the Firebase collection like this:
const admin = require("firebase-admin");
const arr = ["id1", "id2"];
const refArr = arr.map(id => admin.firestore().collection("media").doc(id));
const m = await admin
.firestore()
.collection("media")
.where(admin.firestore.FieldPath.documentId(), "in", refArr)
.get();
This last example is from this discussion
If you are looking for more dynamic queries with a helper function, you can simply try this.
import { db} from '#lib/firebase';
import {query, collection, getDocs ,documentId } from "firebase/firestore";
const getResult = async (_value) => {
const _docId = documentId()
const _query = [{
field: _docID,
operator: '==',
value: _value
}]
// calling function
const result = await getDocumentsByQuery("collectionName", qColl)
console.log("job result: ", result)
}
// can accept multiple query args
const getDocumentsByQuery = async (collectionName, queries) => {
const queryArgs = [];
queries.forEach(q => {
queryArgs.push(
where(q.field, q.operator, q.value)
);
});
const _query = query(collection(db, collectionName), ...queryArgs);
const querySn = await getDocs(_query);
const documents = [];
querySn.forEach(doc => {
documents.push({ id: doc.id, ...doc.data() });
});
return documents[0];
};
From Firestore docs for Get a document.
var docRef = db.collection("cities").doc("SF");
docRef.get().then(function(doc) {
if (doc.exists) {
console.log("Document data:", doc.data());
} else {
// doc.data() will be undefined in this case
console.log("No such document!");
}
}).catch(function(error) {
console.log("Error getting document:", error);
});
This is the first link that came up when I was looking to solve it in the Golang SDK, so I'll add my solution in case anyone else is looking for it:
package main
import (
"context"
"fmt"
"log"
"cloud.google.com/go/firestore"
firebase "firebase.google.com/go/v4"
"google.golang.org/api/option"
)
type (
Car struct {
ID string
Name string `firestore:"name"`
Make string `firestore:"make"`
Price float64 `firestore:"make"`
}
)
func main() {
ctx := context.Background()
// Use a service account
options := option.WithCredentialsFile("PATH/TO/SERVICE/FILE.json")
// Set project id
conf := &firebase.Config{ProjectID: "PROJECT_NAME"}
// Initialize app
app, err := firebase.NewApp(ctx, conf, options)
if err != nil {
log.Fatal(err)
}
// Get firestore client
client, err := app.Firestore(ctx)
if err != nil {
log.Fatal(err)
}
defer client.Close()
collectionRef := client.Collection("CAR_COLLECTION")
// firestore.DocumentID == "__name__"
docSnap, err := collectionRef.Where(firestore.DocumentID, "==", collectionRef.Doc("001")).Get(ctx)
if err != nil {
log.Fatal(err)
}
// Unmarshall item
car := Car{}
docSnap.DataTo(&car)
car.ID = docSnap.Ref.ID
// Print car list
fmt.Println(car)
}
Just to clear confusion here
Remember, You should use async/await to fetch data whether fetching full collection or a single doc.
async function someFunction(){
await db.collection('books').doc('fK3ddutEpD2qQqRMXNW5').get();
}

firebase / firestore docs queries Not working - javascript

As firestore is new, i am having problems using it.
I have to get Collection of all users and traverse it. But it is not working.
db.collection("users").get().then(function(querySnapshot){
console.log(querySnapshot.data());
});
It says:
querySnapshot.data is not a function
And following code:
callFireBase(mobileToCheck){
db.collection("users").where("mobile_no", '==', mobileToCheck).get().then(function(querySnapshot){
if (querySnapshot.exists) {
var userData = querySnapshot.data();
var userId = querySnapshot.id;
console.log(mobileToCheck + "Exist In DB");
}else{
console.log(mobileToCheck + "Do Not Exist In DB");
}
});
}
Is always printing
923052273575 Do Not Exist In DB
Even if it exists, See following image for reference. In docs they have told this (i have used) way.
It looks that tou want to call.data() on collection of documents, not one document. Please see if this code works:
db.collection("users").get().then(function(querySnapshot){
querySnapshot.forEach(doc => {
console.log(doc.data());
});
}).catch(err => {
console.log('Error getting documents', err);
});
You should use docs.map then doc.data(). Here is how to do it with Firestore using async await syntax
import firebase from 'react-native-firebase'
async fetchTop() {
const ref = firebase.firestore().collection('people')
const snapshot = await ref.orderBy('point').limit(30).get()
return snapshot.docs.map((doc) => {
return doc.data()
})
}

Categories