how to get documents with user information (firestore) - javascript

I have collection with documents.
Structure (fields):
questions
- question
- userID
and my project uses Firebase Authentication. How to get questions with data about author of each question (avatar and name) in javascript.

You need to store every user in collection (ex. 'users' ) after register, and then make leftJoin with both questions and users collections.
something like this:
async function getQuestionsWithAuthors() {
const result = [];
const questionsSnap = await firebase.firestore().collection('questions').get();
for(const doc of questionsSnap.docs) {
const questionData = doc.data();
const userData = await firebase.firestore().collection('users').doc(questionData.userID).get();
result.push({...questionData, user: userData});
}
return result
}

Related

How do I query a collection of firebase documents by a properties value?

I am a building a Firebase React social media app with a search bar, I want my searchbar to show suggestions of users based on the value of input. If I type "F" I expect Foo and then underneath Bar, pretty much like any social media search bar that filters the users and returns the relevant ones. . I am having trouble understanding the Firebase queries and what would be appropriate for this.
The Layout of the DB is
users collections
documents that represent a user
a username property on the document
const searchUser = async (text) => {
const queryUsers = [];
if (text !== '') {
try {
const usersRef = collection(firestore, "users");
const q = query(usersRef, orderBy("username"),startAt(text.toLowerCase()),limit(5))
const querySnapshot = await getDocs(q)
querySnapshot.forEach((doc) => {
queryUsers.push(doc.data())
})
} catch (error) {
console.error(error);
}
}
console.log(queryUsers);
return queryUsers;
};
I tried all sorts of queries but none of them worked, I am expecting to get all the users ordered by the value of the string that was sent to the query
Found the issue, the username was saved with a Capital letter. Not sure if this query is also the best one.

Firebase Query and how to read the output

Above is my Js code
I have a database that has information regarding the location of an apartment, I am trying to search for a specific property to see if it exists in the database. The user will be able to key into the search box to perform the search.
"propertiesRef" is used to store the user input.
I tried storing the data into "q" that I received from querying the database. But I have no idea how to read the result.
This is the console log for "q", but I don't quite understand the information that is shown, I want to know which output in the console should I be looking at and how do I access them?
The query() function just creates an instance Query. You need to use getDocs() function to actually fetch data from Firestore.
const search = (property) => {
const propertiesRef = collection(db, "flats-table");
const q = query(propertiesRef, where("name", "==", property))
return getDocs(q).then((qSnap) => {
const data = qSnap.docs.map(d => ({ id: d.id, ...d.data() }))
console.log(data);
return data;
})
// or use async-await
// const qSnap = await getDocs(q);
}
Checkout the documentation for more examples.

react native firebase How to check if chatroom already exist

Hi I would like to check if chatroom already exist. and I don't want to make another chatroom with the same person. I searched it a lot and I found this code but it didn't work for me. I can make a lot of chatroom with the same person.
same chatrooms
like that
firebase data
if you help me I'd really appreciate it.
const userChatRef = db
.collection('chats')
.where('users', 'array-contains', user.email);
const [chatsSnapshot] = useCollection(userChatRef);
const makeRoom = () => {
if (user.email !== email && !chatAlreadyExists(email)) {
db.collection('chats')
.add({
users: [user.email, email],
})
.then(doc => {
navigate(MESSAGEROOM, {id: doc.id, recipientEmail: email});
});
} else {
alert('Already exist!');
}
};
const chatAlreadyExists = recipientEmail => {
!!chatsSnapshot?.docs.find(
chat =>
chat.data().users.find(userEmail => userEmail === recipientEmail)?.length > 0,
);
Unfortunately you currently can't have more than one 'array-contains' statements in a firebase query. I would suggest to simply do the following:
const checkForDuplicateChat = (userid1, userid2) => {
const db = firebase.firestore()
// fetching all chats of bb#naver.com
// userid1 = e.g. bb#naver.com
let chats = db.collection('chats').where('users', 'array-contains', userid1).get()
// mapping the parsed json data in the array
data = data.docs.map(el => el.data())
// el.users.length === 2 to check if it is a chat existing only
// between user1 and user2 (excluding groupchats etc.)
// userid2 = f.e. dd#naver.com
data = data.filter(el => el.users.length === 2 && el.users.includes(userid2))
if(data.length > 0) return // what ever happens when there already is a chat
createChat(user1, user2)
}
I hope this helps at first, but keep in mind you will have a ton of reads when all users have a lot of chats, because you always have to fetch all the chats of the user before filtering out.
EDIT:
You also could add an Array to the document of each user, which lists all other users he has a chat with like:
bb#naver.com:{
mail: "bb#naver.com",
hasChatWith: [
"dd#naver.com",
"cc#naver.com",
"ee#naver.com"
]
}
So in this case you just have to check the array hasChatWith of bb#naver.com before he opens a chat. If you open a new chat make sure you add both users to eachothers list.

firebase.firestore() shows bizarre data and not my actual documents from the database/

I am querying firebase firestore by...
let database = firebase.firestore();
let places = database.collection("place");
console.log("places", places);
now the logged data is bizarre and not the actual documents..
here is a picture of the log...can you please advice regarding tackling this ?
If you want to retrieve all items in your collections called "place" you can do something like this:
let database = firebase.firestore();
let places = database.collection("place");
const querySnapshot = places.get()
// You can make an empty array to eventually push the items into
const collectionArray = []
querySnapshot.forEach((doc) => {
const data = doc.data()
collectionArray.push(data)
}).catch(function(error) {
console.log("Error getting documents: ", error);
})
console.log('collectionArray:',collectionArray)
}
Your code hasn't actually executed any query yet. All it's done is build a Query object.
If you want to execute the query, call get() on it, and handle the results as shown in the documentation.
let database = firebase.firestore();
let query = database.collection("place");
query.get()
.then(querySnapshot => {
querySnapshot.forEach(documentSnapshot => {
console.log("document", documentSnapshot.data());
})
})

Filtering data in Firebase

I'm matching a user in a list of users as follows:
export async function getLoginData(uid) {
let loginData;
const usersRef = await database.ref('users');
const snap = await usersRef.once('value');
snap.forEach((item) => {
const itemVal = item.val();
if (itemVal.uid === uid) {
loginData = itemVal;
}
});
return loginData;
}
Style-wise, I'm not a fan of this. I'd much rather do a filter for the matching:
loginData = snap.filter((item) => item.val().uid === uid);
But the filter method is not available in the snapshot. Is there a way to write more clean, one line retrievals of data from Firebase? Or does it always have to be a forEach and a callback as I have above?
Before worrying about the style of your current filtering approach, it's probably better to consider its performance. You're downloading all data under the /users node to then filter out anything where item.val().uid <> uid. Such client-side filtering wastes your user's bandwidth.
You should instead use Firebase's built-in querying capabilities where possible. In this case it seems quite simple:
let loginData;
const usersRef = await database.ref('users');
const snap = await usersRef.orderByChild('uid').equalTo(uid).once('value');
snap.forEach((item) => {
const itemVal = item.val();
loginData = itemVal;
});
In this case you still need to loop. Since a query can potentially match multiple child nodes, the code needs to deal with this situation.
If you are certain that each user node has a unique UID, you should consider storing the user data with that UID as the key (instead of another generated key):
users
uid1
name: "user2878765"
uid2
name: "Frank van Puffelen"
Storing the user data under the key automatically ensures that the UID is unique and makes it that you can look up the user's data without requiring a query. That also means you don't need a forEach() anymore:
let loginData;
const usersRef = await database.ref('users');
const snap = await usersRef.child(uid).once('value');
const itemVal = snap.val();
loginData = itemVal;
That also makes it easier to return the correct promise from your function:
export async function getLoginData(uid) {
const snap = await database.ref('users').child(uid).once('value');
return snap.val();
}

Categories

Resources