access subcollection in firebase firestore v9 - javascript

I'm trying to access the firebase firestore documents inside subcollection (messages):
user > user.uid > messages > docRef.id > date: Date.now()
text: userText
userEmail: user.email
userName: display.name
I used the following:
const snapRef2 = collection(db, "users/" + user.uid + "/messages")
onSnapshot(snapRef2, (snapshot) => {
snapshot.forEach((doc) => {
console.log(doc.data());
})
})
But this method works only when user.uid is a string like: const snapRef2 = collection(db, "users/randomstring/messages")
How do I access the documents inside messages?

const snapRef2 = collection(db, `users/${user.uid}/messages`)
Make sure to use back ticks instead of quotation marks

The code in your answer works if you want to retrieve the messages for a specific user, identified by user.uid.
If you want to get the messages for all users, you can use a collection group query. Such a query reads from all collections with a specific name, like messages:
const snapRef2 = collectionGroup(db, "messages")
...
The rest of your code can stay the same.

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);

How can I get documents from Firestore for current user?

I'm trying do display data from Firestore database in my component.
This is my function:
const getData = async () => {
const data = [];
const querySnapshot = await getDocs(
collection(databaseRef, "mK7DFNJgRAPmtvgrZh7X6AOj8cR2")
);
console.log(querySnapshot);
querySnapshot.forEach((doc) => {
console.log(doc.id, " => ", doc.data().Title);
data.push({
About: doc.data().About,
Title: doc.data().Title,
Who: doc.data().Who,
});
});
setData(data);
};
Collection ID = Current logged in User.
I want to display every document.
Everything works fine but insteed of passing hard-coded string here:
collection(databaseRef, "mK7DFNJgRAPmtvgrZh7X6AOj8cR2")
I would like to pass variable where I store my UID.
Is there any way to do that?
Assuming your user is logged in, you should be able to access their UID via firebase.auth().currentUser.uid. This question's answers may be useful for more information on getting the current user's ID.
With that, you should be able to do:
const querySnapshot = await getDocs(
collection(databaseRef, firebase.auth().currentUser.uid)
);
to get the current user's documents.
https://firebase.google.com/docs/reference/js/v8/firebase.auth.Auth#currentuser

Join Search Query on firebase, how?

I am trying to conduct simple search query as below.
SELECT post.title as "Post Title", user.email as "Author Email"
FROM User
JOIN Post ON User.id = Post.userID
WHERE Post.title LIKE '%retriever%';
I know I can't do join search on nested collection
so I ended up creating two root collections: users, posts.
Below is my pathetic try on such query
const db = firebase.firestore()
const ref = db.collection('Post')
const postTitle = await ref
.orderBy('title')
.startAt('Springfield')
.get();
const userEmail = await db.collection('User')
.where('id', '==', 'postTitle.userId')
.document('email');
How do I achieve the above result in this particular case?
Alright, first let me confirm I understand the SQL.
You're wanting to return two variables (title, email) from the User table
SELECT post.title as "Post Title", user.email as "Author Email"
FROM User
Then you want to join the Post table where the 'User.id' is equal to the 'Post.userID' so essentially finding the users' posts.
JOIN Post ON User.id = Post.userID
WHERE Post.title LIKE '%retriever%';
If my assessment is accurate, and without knowing your data model, I can give a rough guess on what that would look like.
//Reference to Firestore
const db = firebase.firestore()
//Reference to the Post "table" Collection
const ref = db.collection('Post')
//This is assuming I know the USER ID that I need - if I don't have it, we can retrieve it by their email 'admin.auth().getUserByEmail(email)' or somewhere else.
//This example should still work with whatever the 'id' key is representing in the Post model
const postsByUserID = await ref.where('id', '==', userID).get();
if (postsByUserID.empty) {
console.log('No matching documents.');
return;
}
//This will loop through every Post that we got that matched the user's ID
postsByUserID.forEach(doc => {
console.log(doc.id, '=>', doc.data());
});
Keep in mind this is assuming that 'id' from your Post model is equal to a user's UID.
If we assume we do not know the user's ID, and want to get every user, and then the posts that have the 'id' equal to that user's id:
//Reference to the Post "table" Collection
const ref = db.collection('Users')
const allUsers = await ref.get();
allUsers.forEach(doc => {
console.log(doc.id, '=>', doc.data());
const userID = doc.data().id;
const postsByUserID = await ref.where('id', '==', userID).get();
if (postsByUserID.empty) {
console.log('No matching documents.');
return;
}
//This will loop through every Post that we got that matched the user's ID
postsByUserID.forEach(doc => {
console.log(doc.id, '=>', doc.data());
});
});

How to access a different collection within a firebase function

I promise i thoroughly checked through all the previous asked questions and there isn't anything similar to this. I have a firebase function that listens to onCreate on a firestore collection.
exports.sendEmail = functions.firestore.document('/Users/{documentId}')
.onCreate((snap, context) => {
const username = snap.data().username;
const email = snap.data().email;
console.log(username, email)
const mailRef = functions.firestore.document('/mail')
return mailRef.ref.set({
email: email,
subject: 'Welcome'
});
});
After a document is created in Users, i want to take the data in users and create a new document in a main collection called mail. Is this possible because i've read the docs like 10 times and there's nothing on this. Any help is highly appreciated.
To create a document in cloud functions, then you need to use the admin sdk, so first install the package:
npm install firebase-admin --save
initialize the admin sdk:
const admin = require('firebase-admin');
admin.initializeApp({
credential: admin.credential.applicationDefault()
});
const db = admin.firestore();
Then you can add:
const mailRef = db.collection('mail')
return mailRef.add({
email: email,
subject: 'Welcome'
});
https://googleapis.dev/nodejs/firestore/latest/CollectionReference.html#add
I know this is coming a bit late, just incase anyone found themselves with this same question.When you use set() to create a document, you must specify an ID for the document to create. so basically the above code just takes a little tweak as follows
exports.sendEmail = functions.firestore.document('/Users/{documentId}')
.onCreate((snap, context) => {
const username = snap.data().username;
const email = snap.data().email;
const uid = context.params.documentId //get the doc ID
const alternateUid = //you can generate a random ID here
console.log(username, email)
const mailRef = firestore.collection("mail").doc(uid)
return mailRef.set({
email: email,
subject: 'Welcome'
});
});
But sometimes there isn't a meaningful ID for the document or you don't want to use any of the above. Then it's more convenient to let Cloud Firestore auto-generate an ID for you. You can do this by calling add(), as such
const mailRef = firestore.collection("mail")
return mailRef.add({
email: email,
subject: 'Welcome'
})

How to read data from firestore database without trigger functions in index.js file?

I have stored some data in firestore. There is collection(books) which link to document(book id)and book id has field like name, image,location,title.
I have another collection(Users) which has document(user id)user id has field as token id .Whenever there will be any write operation in book collection then I have to send notification to all the user using token id .
I am able to send notification to all user if I have hard-coded token id in my index.js file of firestore.
But I have to send notification dynamically. I am not able to read user id from collection users.
'use-strict'
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);
exports.sendNotification = functions.firestore.document("Books/{book_id}").onWrite((change, context) => {
const book_id = context.params.book_id;
console.log("Book ID: " + book_id);
return admin.firestore().collection("Users").doc(user_id).collection("Notifications").doc(notification_id).get().then(queryResult => {
const tokenid= queryResult.data();
const token_id='fOGd94em4ik:APA91bHyZBGBYvO_ZFlLO1lWL1LU-r-1JkuF3fuKieWvV4HuPDKAiG5hdn-BQrMPFeICBdKZ3UR2nkM2PMxClEzVI3V2C38OxoP-1w71Dz-GbO0sbDlg-nswCMZ';
const payload = {
notification : {
title : 'Hi',
body : 'New Books list is available in the database! Please check the book store',
icon : "default"
}
};
return admin.messaging().sendToDevice(token_id, payload).then(result => {
//console.log("Notification sent");
return 0;
});
});
});
In above code I want to read user_id from collection users. How can I read it since it is not linked with collection books ,I am not able to read.
If I understand well and if token_id is a key in users record, you may try something like this:
admin.firestore().collection('Users')
.where('token_id', '==', 'YOUR_TOKEN').get()
.then(snap => snap.docs.map(user => {
// iterate on your notification process
})

Categories