Trouble accessing firebase query results in document template - javascript

new to vue and firebase but stuck on this for hours. I have a vue3 app running a specific firebase9 query that will only return a maximum of 1 row (i.e. includes limit 1). The results are being returned but I am having trouble accessing the data so I can pass up to the template. I am using an example from a tutorial that was designed to return multiple rows from FB then iterate through in the template using v-for but in this case it will only ever be one row. All the tutorials I can find are similar not addressing how to deal with one row (or document) being returned. Oddly, the data is being returned to _rawValue but I can't seem to get to it...
Here's the JS snippet:
let collectionRef = collection(db, c)
collectionRef = query(collectionRef, where(...q), orderBy(...ob), limit(...lmt))
const unsub = onSnapshot(collectionRef, snapshot => {
let results = []
snapshot.docs.forEach(doc => {
results.push({ ...doc.data(), id: doc.id })
})
// update values
documents.value = results
})
return { documents }
Here's the Vue snippet:
const { documents: lastEvent } = getCollectionRt(
'events',
['userId', '==', user.value.uid],
['created', 'desc'],
['1']
)
console.log('lastevent: ', lastEvent)
I can see that lastEvent does indeed contain an array with the values I am looking for so the query is running and returning, BUT, it is listed in something called "_rawValue" that I can't seem to access. For example I would like to set a variable to one of the values being returned like let myVar = lastEvent.id or lastEvent.created, etc.
[edit: use case is that I want to query the users last input so I that can set some of the form data default values based on their last entry]
Any help or reference to get me unstuck would be greatly appreciated.
Screenshot of console.log

Came up with a solution. Probably hacky but works.
First modify the getCollectionRt.js that runs the query as
...
const document = ref(null)
collectionRef = query(collectionRef, where(...q), orderBy(...ob), limit(...lmt))
const unsub = onSnapshot(collectionRef, snapshot => {
let results = []
snapshot.docs.forEach(doc => {
results.push({ ...doc.data(), id: doc.id })
document.value = { ...doc.data(), id: doc.id }
})
// update values
documents.value = results
})
return { documents, document }
then pull in 'document' and return in vue as:
const { documents: lastEvent, document } = getCollectionRt(
'events',
['userId', '==', user.value.uid],
['created', 'desc'],
['1']
)
...
return {..., document }
then I can access it in the template as {{ document.id}}
Although this works, definitely spend more time learning about workign with object/arrays in VueJS

Related

How to get all documents on a nested firebase collection

I have a nested subcollection that looks like:
users > user.id > cart > doc.id
And I am trying to get ALL documents on that collection. Here's how I get a single one:
useEffect(() => {
const getStyleProfile = async (user: any) => {
if (user) {
const docRef = doc(db, "users", `${user.uid}`, 'cart', `${1}`);
onSnapshot(docRef, (doc) => {
setStyleProfile(doc.data())
});
}
}
getStyleProfile(user)
}, [user?.uid])
Which returns the first document:
{price: 400, property_id: 1} 'style values'
My question is: how can I return all the documents, no matter the ID?
Any question I've seen doesn't relate to subcollections, so not sure how to get it working, e.g this one
As shown in the documentation, you build a reference to a collection like this:
const usersCollectionRef = collection(db, 'users');
You build a reference to a subcollection in much the same way:
const userCartsCollectionRef = collection(db, 'users', uid, 'carts);
The collection reference is queried exactly the same way no matter how deeply nested it is, as illustrated in the documentation.
const querySnapshot = await getDocs(userCartsCollectionRef);

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 fetch all the documents with unique id from firestore database using React?

[Firestore SS][1]
[1]: https://i.stack.imgur.com/EI1Dm.png
I want to fetch each document as displayed in SS it's stored as Pets + unique_userId.
I am unable to fetch all data together. Just able to fetch one data of a particular user using the code below.
const [info,setInfo]=useState([]);
useEffect(() => {
db.collection("pets ESYXOPqlJpZ48np8LfNivnh9pvc2").onSnapshot((snapshot) =>
setInfo(snapshot.docs.map((doc) => doc.data()))
);
},[]);
Here ESYXOPqlJpZ48np8LfNivnh9pvc2 this is the userID of each unique user
Please help me out to fetch all the Pets data instead of hardcoding and fetching one particular data.
Try the following code,
const [docs, setDocs] = useState([]);
useEffect(() => {
const querySnapshot = await getDocs(collection(db,"pets ESYXOPqlJpZ48np8LfNivnh9pvc2"));
const document =[];
querySnapshot.forEach((doc) => {
document.push({
...doc.data(),
id: doc.id
});
});
setdocs(document);
}, []);
I'm guessing the appended id is a reference to the owner's id? In this case, would it be an option to fetch the owner list and use everyone's id to build a list of collection ids and then get all of their data?
If not, I only see to options:
Rethink your database structure - maybe use a unified pets collection and have a reference with/to that id in the pet documents.
Create a cloud function in which use #google-cloud/firestore to get the list of collections. There are tons of resources out there to help you get started with firebase cloud functions. Their documentation is pretty good also, and probably the most up-to-date
const functions = require('firebase-functions')
const { Firestore } = require('#google-cloud/firestore');
module.exports = functions
.region('europe-west3') // use the region you want here
.https.onRequest(async (request, response) => {
try {
const firestore = new Firestore();
const collections = (await firestore.listCollections()).map(collection => collection.id)
response.json({ data: collections })
} catch (error) {
response.status(500).send(error.message)
}
})
You'll get and endpoint which you can use to fetch the collection ids (e.g.: https://your-project-name.cloudfunctions.net/collections)
const [pets, setPets] = useState([]);
const [collectionIds, setCollectionIds] = useState([])
useEffect(() => {
fetch('https://your-project-name.cloudfunctions.net/collections')
.then(response => response.json())
.then(({ data }) => setCollectionIds(data))
}, [])
useEffect(() => {
collectionIds.forEach((collectionId) => {
// There are better ways to do this,
// I'm just using your approach so you can focus on the rest of the code
db.collection(collectionId).onSnapshot((snapshot) => {
setPets((currentPets) => [...currentPets, ...snapshot.docs.map((doc) => doc.data())])
})
})
}, [collectionIds])
Please note that these are very high-level implementations, there's no error handling, no teardowns or anything, so keep that in mind. Hope it helps, good luck!

Why does my DBSearch function keep looping when pulling data from Firebase?

New to coding last month and I'm learning JS through React Native.
I've added a Firestore DB to pull data through to my app and put together a call-back function using the useState hook due to it being Async.
My issue is my DBSearch function is now looping infinitely.
Code below:
const [propertyData, setPropertyData] = React.useState(["Well, this is awkward..."])
const colRef = (listName) => collection(db, listName)
const dbSearch = (listName, callBackFuncHere) => {onSnapshot(colRef(listName), (snapshot) => {
let newList = []
snapshot.docs.forEach(doc => {
newList.push({ ...doc.data(), id: doc.id }) // Pulls Object Data and runs for loop to assign to newList Array
})
callBackFuncHere(newList)
})};
function retFunc(newList){
setPropertyData(newList)
console.log('1')
}
dbSearch('propertyList', retFunc)
Is this an improper use for useState? and how should I change my dbSearch function to stop it continually looping?
Apologies if this has been asked a thousand times before, I'm unsure how to clearly articulate and search for my problem.

How to get two queries from firestore?

I use redux and want to know how to take and process two queries from firesotre.
export function getBlackList(data) {
return (dispatch, getState) => {
let db = loadFB().firestore();
let query = db.collection('users').where("report.total_point",">",0).orderBy("report.total_point","asc");
return query.get().then(docs=>{
let result = [];
console.log(result);
docs.forEach(doc=>{
let user = doc.data();
user.id = doc.id;
result.push(user);
})
dispatch({
type: types.SET_USER_LIST,
data: result,
page : 1
})
})
}
}
Through the code presented above, the component is processed through dispatch.
I get a query But I want to know how to get the two query values ​​together and sort them.
db.collection('users').where("memo",">","0").orderBy("memo","asc");
Is there a way to solve it using "promise all"?
Look forward to a good solution.
You can't use Promise.all to query two values from a same collection, Promise.all is used to retrieve data from a collection group [different collections] instead of from a single collection.
In order to query two values together, use the code below:
let query: db.collection('users').where("memo",">","0").where("memo2","<","3");
And after you can sort them:
query.orderBy("memo","asc");
Your query will return multiple items. Get them together you can use map and sort if you need.
Then the call to dispatch for redux looks ok to me.
query.get().then(docs => {
const users = docs.map(doc => ({
id: doc.id,
...doc.data(),
}));
// .sort(...)
dispatch({
type: types.SET_USER_LIST,
data: users,
page: 1,
});
});

Categories