How to query documents from an array in firebase JS - javascript

and thanks in advance if anyone can help with this.
I am attempting to fetch all the posts that a user is following.
I store who a user is following in an array like so: [uid, uid, uid, ...]
step 1: get who a user is following
step 2: get the posts of the users in the user the following array
i.e. get the posts of all these people -> [uid, uid, uid, ...]
issue: after step 2 I recieve [user1posts],[user2posts],[user3posts], ......
the 'posts' will actually flicker all the user's posts in order and then display the last user in the array's posts permanently.
desired: after step 2 I would receive [ user1posts, user2posts, user3posts, ... ]
so:
currently = posts: [user1posts],[user2posts],[user3posts], ......
desired = posts: [ user1posts, user2posts, user3posts, ... ]
const [posts, setPosts] = useState([]);
const [refreshing, setRefreshing] = useState(false)
useEffect(() => {
function fetchUserFollowing(){
firebase.firestore()
.collection('users')
.doc(firebase.auth().currentUser.uid)
.onSnapshot((snapshot) => {
let following = snapshot.data().following
for(let i = 0; i < following.length; i++)
fetchUsersFollowingPosts(following[i])
})
}
function fetchUsersFollowingPosts(uid){
firebase.firestorm()
.collection('posts')
.doc(uid)
.collection('todaysPosts')
.orderBy('createdAt','desc')
.onSnapshot((snapshot) => {
let posts = snapshot.docs.map(doc =>{
const data = doc.data()
const id = doc.id;
return({id, ...data})
})
setPosts([...posts])
})
}
fetchUserFollowing()
}, [props.currentUser && props.currentUser.following])
recap: this returns a separate array for each user. I've been attempting to get all the arrays into one single array. I'm sure it's an easy fix, however, I cannot figure this out for the life of me.
thanks again
I have tried lots of workarounds

Related

Is there a way to use .where() to check an array's field exact values?

I'm building an app using React Native and Firebase. I have this problem where I have to check the presence of a document that has an array field called members, and this field needs to have two exact values besides the order. The problem is that I don't know how to do it. Below there's what I achieved till now.
export const findRightChat = (contactId, userId) => {
let temp = [userId, contactId]
firebase.firestore()
.collection('chats')
.where('members', '==', temp)
.get()
.then((res) => {
const chat = res.docs.map((value) => {
const id = value.id;
const data = value.data();
return {id, ...data}
})
console.log(chat)
})}
Now this works only when the fields in members are: contactId, userId, but not when they are: userId, contactId. Any help?

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(),
}));

Trouble accessing firebase query results in document template

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

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!

Categories