For my React application, i am attempting to write a custom hook to be used for querying a Firestore database in Firebase.
So far i wrote a hook that uses a pre-defined query which works. What i cannot figure out is how to write a function capable of dynamically generating that query.
Here is what i have so far:
import { useState, useCallback } from 'react';
import { initializeApp } from "firebase/app";
import { getFirestore, getDocs, collection, query, where, orderBy, limit } from 'firebase/firestore';
import firebaseConfig from "./firebase.config";
const useQuery = () => {
// NOTE for clarity i am showing initialization of firebase here
// although this actually happens in another file and is imported.
const firebaseApp = initializeApp(firebaseConfig);
const firestore = getFirestore(firebaseApp);
const firestoreRef = collection(firestore, 'myCollection');
const [snapshot, setSnapshot] = useState([]);
const getSnapshot = useCallback(async(queryConstraints:any) => {
// instead of this pre-defined query ...
const firestoreQuery = query(firestoreRef,
where('someField', '>=', 'someValue'),
where('anotherField', '==', 'anotherValue'),
orderBy('timestamp', 'asc'),
limit(10)
);
// ... Id like to be able to take the incoming argument
// titled 'queryConstraints' of which its value
// would be an object like this one:
// {[{
// where: 'someField',
// operator: '>=',
// value: 'someValue'
// },{
// where: 'anotherField',
// operator: '==',
// value: 'anotherValue'
// }], 10, 'timestamp', 'asc'}
// ... and pass it to a function, lets call it 'configAValidQuery' which
// would parse the object and return a valid query to be applied as follows:
// const myQuery = await configAValidQuery(queryConstraints);
// const firestoreQuery = query(firestoreRef, myQuery);
try {
const docs = await getDocs(firestoreQuery);
if(docs.empty) {
// TO DO: HANDLE EMPTY RESULT
} else {
setSnapshot(doc.data());
}
} catch(error:any) {
// TO DO: HANDLE ERROR
}
}, [firestoreRef]);
return {
snapshot,
getSnapshot
}
}
export default useQuery;
I am having trouble figuring out how to construct what basically amounts to a comma delimited list of function calls dynamically, given that the query constraints consist of the imported firebase methods where, orderBy and limit.
The function i need would look something like the following, although this would obviously not work:
const configAValidQuery = useCallback((conditions:any, limit:number, orderBy:string, direction:string) => {
let query:any;
if(conditions.length > 0) {
conditions.map((item:any) => {
return(query = query.where(item.where, item.operator, item.value))
});
query = query.orderBy(orderBy, direction);
if(limit > 0) {
query = query.limit(limit);
}
return query;
} else {
query = query.orderBy(orderBy, direction);
if(limit > 0) {
query = query.limit(limit);
}
return query;
}
},[]);
The firebase/firestore package does not appear to contain a pre-defined interface or function for this purpose.
Any suggestions?