Firebase 9 get single document from nested collections - React - javascript

This is my first time asking a question on here, usually I can find what I'm looking for, but I am upgrading from Firebase 8 to Firebase 9 in an ionic/react FC app, and have got some of it figured out, but I cannot figure out how to get a single document from nested collections. In Firebase 8 it would look like:
db.collection('department').doc(deptId).collection('employees').doc(empId).get()...
I have tried a couple ways with collectionGroup, and don't get anything returned at all, but I'm not even sure that is the correct way to go. Any help would be greatly appreciated!! Thanks!

If you already know syntax (and how Firebase works) of Firebase JS SDK (V8 and before), I'll highly recommend checking out the documentation as they have syntax of both side by side. Just click on the modular tab in documentation. Fetching a single document will be as shown below:
import { doc, getDoc } from "firebase/firestore";
const docRef = doc(db, "department", deptId, "employees", empId);
const docSnap = await getDoc(docRef);
if (docSnap.exists()) {
console.log("Document data:", docSnap.data());
} else {
console.log("No such document!");
}
Also checkout: Firestore: What's the pattern for adding new data in Web v9?

Related

Firebase 9 deleteDoc to delete a document is not working - Uncaught TypeError: Cannot read properties of null (reading 'name')

I am using Firebase 9 as a backend for my small experimental app. I have two collections called "Playernames" and "Players". Playernames collection has one document that contains only one key. The collection "Players" contains multiple user documents by uid. Each each user document contain a subcollection called "collections" that contains just one document.
Over this, I have implemented Email/Password Authentication.
Part of app functionality, I am trying to delete the user. I have written async function as below:
export const deleteUsersData = async (name) => {
await updateDoc(doc(colRefPn, "unames"), { names: arrayRemove(name) });
await deleteDoc(doc(db, "players", auth.currentUser.uid, "collections", "robodata"));
await deleteDoc(doc(db, "players", auth.currentUser.uid)); //PROBLEM LINE
try {
await deleteUser(auth.currentUser);
} catch {
//Reauthenticate the user
await reAuthenticateUser();
await deleteUser(auth.currentUser);
}
};
I am calling this function in another file like below:
deleteUsersData(currentUserData.name)
.then(() => {
Swal.fire("Account Deleted!", "Your account has been deleted. You have been signed out automatically.", "success");
handleSignout();
})
.catch((ex) => {
Swal.fire("Could not delete!", "There was an error deleting the user.", "error");
console.error("There was an error deleting the user", ex.message);
});
In the above code, I use Sweetalert2 library to fire some popups.
I have marked the line in the above code as "PROBLEM LINE". This is where the problem is occuring. If I comment this line, everything works good. Of course, the document in players collection does not get deleted leading to incomplete deletion of user. I am following guidelines exactly how Firbase has specified in their document. I do not understand why this line throwing the below error in the console.
I have attached the console log file here and some screenshots on what I errors I am seeing. Could someone please help me out what I am missing here. [a few screenshots](https://i.stack.imgur.com/P4nPW.png)
LogFile
I tried to delete the user using Firebase prescribed APIs. I was expecting that the user collection would be deleted. But, that did not happen. I am getting the error.
Console log showing the value of currentUserData:
However, the problem is not with the currentUserData. This problem in the line:
await deleteDoc(doc(db, "players", auth.currentUser.uid));
I did try to delete the document replacing auth.currentUser.uid with actual uid (hardcoding). That also did not work. This is what Firebase documentation says how to delete a document. Not sure what I am doing wrong.
Here are some snapshots from firebase:
Screenshot 1
Screenshot 2
I fixed this issue by eliminating await keyword in front of firebase functions. For me it is not making sense why this worked while Firebase documentation suggests that these functions should be used behind the await keyword. Here is how my working deleteUsersData function looks:
export const deleteUsersData = async (name) => {
updateDoc(doc(colRefPn, "unames"), { names: arrayRemove(name) });
deleteDoc(doc(db, "players", auth.currentUser.uid, "collections", "robodata"));
deleteDoc(doc(db, "players", auth.currentUser.uid)); //PROBLEM LINE
try {
deleteUser(auth.currentUser);
} catch {
//Reauthenticate the user
await reAuthenticateUser();
deleteUser(auth.currentUser);
}
};
I hope this helps someone who is facing the same issue as me. I spent a day on this, pulling my hair off.

Have an empty docs in querySnaphsot when trying to get data with firebase

I recently developped a firebase schedule function to retrieve data on every monday.
I tested it during the previous days and it was working correctly. However, this morning, I discovered that my query wasn't able anymore to retrieve data as it used to do. I now have an empty array at QuerySnapshot.docs. You can find my code below:
const functions = require("firebase-functions");
const admin = require("firebase-admin");
admin.initializeApp();
const db = admin.firestore();
exports.scheduledFunction = functions.pubsub.schedule("0 0 * * 1").onRun(async () => {
console.log("start");
const querySnapshotnext = await db.collection("Next_challenges").orderBy("createdAt").get();
console.log("Let see querySnapshot :", querySnapshotnext); //it works, I can see QuerySnapshot object
console.log("Let see docs :", querySnapshotnext.docs); //have an empty array [] even if it should not, it wasn't empty few days ago
console.log("let see the data of the first doc : ", querySnapshotnext.docs[0].data()); //is of course undefined
return null;
});
You can find my database below with the doc that is normally selected:
The rules of my databases are the following :
I don't really understand why my code isn't working anymore, I think it's certainly related to some parameters stuffs and don't really know how I could debug this by myself so don't hesitate to give me some tips so I can be more autonomous with firebase. Thank you :)
Firestore's documentation has a note that says,
An orderBy() clause also filters for existence of the given field. The result set will not include documents that do not contain the given field.
You have .orderBy("createdAt") in your query but there isn't any createdAt field in the documents (at least the one in screenshot). Did you change your document structure recently that is causing this issue?
Also the Admin SDK bypasses any security rules so I'd recommend setting them to false if you don't need to access data directly from client.

How do you find a document by its ID using version 9 of the Firebase JS SDK?

The new version 9 of the Firebase JS SDK has arrived with a more modular approach, and I'm trying to wrap my head around it.
I want to find and read a document from Firestore by its ID. In version 8, you could do:
await db.collection('users').doc(id).get();
Version 9 seems to have a function called "doc", and one called "getDoc", that could sound like the new equivalent, but I don't understand how to use them in practice. Has someone else played around with these yet?
Thanks in advance!
The documentation has a complete code snippet explaining how to fetch a single document with given ID:
import { doc, getDoc } from "firebase/firestore";
const docRef = doc(db, "users", id);
const docSnap = await getDoc(docRef);
if (docSnap.exists()) {
console.log("Document data:", docSnap.data());
} else {
// doc.data() will be undefined in this case
console.log("No such document!");
}
The doc() method is used to get a DocumentReference and getDoc() is used to fetch the document from given reference.

Firebase v9 ,Cannot get document from a nested collection

I feel like it was easier to get subcollection in v8 ,It's been like 2 days trying to do it the new way but I gave up.
Im building a simple react social media app for learning purposes. where each user logs in and be able to post some text (and images but not atm),
I have a main collection for Users and it has the users ID .each of these users have a collection called Posts and it contains all the user posts.
I can do so by entering the UID of each user like so
so what can i do to access the Users collection then get ALL the users and be able to access the Posts subcollection?
ps : sorry if any part of this question is unclear ,english isn't my first language and it's my first time posting here. appreciate any help!.
If you want to fetch posts from all the users, you are looking for collectionGroup queries using which you can fetch documents in all the sub-collections named as 'posts'. You can run a collectionGroup query using Modular SDK (V9) as shown below:
import { getFirestore, getDocs, collectionGroup } from "firebase/firestore"
const db = getFirestore()
const allPosts = await getDocs(collectionGroup(db, "posts"))
const docRef = doc(db, "Users", currentUser.uid);
const docSnap = await getDocs(collection(docRef, "Posts");)

Redirect to checkout in ReactJS

I am trying to implement the Stripe function "redirect to checkout" in ReactJS.
I have been looking around and there is no package that seems to help to do it.
const stripe =
Stripe('key');
stripe.redirectToCheckout({
items: [
// Replace with the ID of your SKU
{sku: 'sku_123', quantity: 1}
],
successUrl: 'https://your-website.com/success',
cancelUrl: 'https://your-website.com/canceled',
}).then(({error}) => {
// If `redirectToCheckout` fails due to a browser or
network
// error, display the localized error message to your
customer
// using `error.message`.
});
This is where I got this source code: https://stripe.com/docs/stripe-js/reference#stripe-redirect-to-checkout
StripeJS only seems to support the standard checkout that does not receive the product SKU as the parameter
After I read the new stripe-js docs https://stripe.com/docs/stripe-js/react
I found this might be useful for you
Instead using stripe, install #stripe/stripe-js
then the job can be done by
import { loadStripe } from "#stripe/stripe-js";
...
const stripePromise = loadStripe(
"pk_.........."
);
const stripe = await stripePromise;
stripe.redirectToCheckout({
...
})
I found out how ti make it work.
Basically as per the documentation, there is the need to import the Stripe script in public/index.html
stripe.redirectToCheckout(...)
can be simply put into the onClick of a button.
The thing that is really not clear in the docs, and that can mislead newbies like me, lies in setting the public key:
const stripe = Stripe('key');
doesn't work, because the script is not found at compile time.
This can be solved by using:
const stripe = window.Stripe('key');
This worked for me.

Categories

Resources