Firebase ver9 adjustment of snapshop/sub collection in React - javascript

I'm trying to replace below code (ver8) to firebase SDK ver9 (modular style). but no success so far.
useEffect(() => {
const unsub = db
.collection("posts")
.doc("postId")
.collection("comments")
.orderBy("timestamp", "desc")
.onSnapshot((snapshot) => {
//update some state
});
return () => {
unsub();
};
}, []);
I tried to use query to access this sub collection together with orderBy by refer to following official example but couldn't find working solution, especially how to handle sub collection reference in query. (how can I realize "collection().doc().collection().orderBy().onSnapshot" in ver9 ?)
I'm really appreciated if someone give me a hint. BR
https://firebase.google.com/docs/firestore/query-data/listen
https://firebase.google.com/docs/firestore/query-data/order-limit-data

As far as I can see in the documentation for the collection function, you can pass in the entire path as a string.
So that should be something like:
...
const db = getFirestore();
const commentsRef = doc(db, "posts", postId, "comments");

#Frank-san Thank you very much for your hint. Now everything working fine with full path arguments (your hint) as like below.
useEffect(() => {
const q = query(
collection(db, "posts", props.postId, "comments"),
orderBy("timestamp", "desc")
);
const unSub = onSnapshot(q, (snapshot) => {
//Some process
});
return () => {
unSub();
};
}, []);
Thanks again and have a good day !

Related

How to get the data of a query from firebase database in react-native

I am trying to list the data of each document that i am fetching from a firebase query, However I am being able to show the data through flatlist, Iwoudl love to iterate the data in another way in order to add it to a PDF that will be created from the app.
const [Annotations, setAnnotations] = useState(null);
useEffect(() => {
const q = query(
collection(db, "notifications"),
orderBy("createdAt", "desc")
);
console.log("Query:");
console.log(q);
onSnapshot(q, (test) => {
setAnnotations(test.docs);
});
}, []);
From the code above I am getting some unneccesary data, however I’d like to get the data of the document, hope you help me, thanks!
What you're seeing are the internals of the Firestore DocumentSnapshot and QueryDocumentSnapshot classes, which is indeed pretty meaningless.
If you only want to use the data:
onSnapshot(q, (test) => {
setAnnotations(test.docs.map((doc) => doc.data()));
});
If you want the data and document ID:
onSnapshot(q, (test) => {
setAnnotations(test.docs.map((doc) => { doc.id, ...doc.data() }));
});

Firebase onSnapshot in react error, "Expected type 'bc', but it was: a custom he object"

I was following this tutorial https://www.sitepoint.com/reddit-clone-react-firebase/.
Earlier it was really simple just call onSnapshot after the document is fetched, but here it is a separate function, and now here comes the issue, when I try to call that onSnapshot by passing document, but it always says,no matter what type of data I tried to pass it as the first param, it always says, it is not type of 'bc' which it expects.
FirebaseError: Expected type 'bc', but it was: a custom he object
useEffect(async () => {
const postsCollection = collection(db, "posts");
const orderedCollection = query(
postsCollection,
orderBy("createdAt", "desc")
);
try {
onSnapshot(
orderedCollection, // here I think the problem is!
(querySnapshot) => {
console.log("yahaan se problem hai");
console.log(querySnapshot);
const _posts = [];
querySnapshot.forEach((doc) => {
console.log(doc);
_posts.push({
id: doc.id,
...doc.data(),
});
});
console.log(_posts);
// setPosts(_posts);
},
(error) => {
console.log("error occured: ", error);
},
() => {
console.log("completed");
}
);
} catch (e) {
console.log("ye kya drama hai:", e);
} finally {
console.log("finally");
}
}, []);
Okey, so I had the same problem and I found a solution after struggling with the newest version of firebase for a while.
I don't know if you're using a class component or a functional one, in this example i'm using a funcional component but I assume it'll work the same if you replace the react hooks.
import { getFirestore, collection } from 'firebase/firestore'
const db = getFirestore();
const colRef = collection(db, "team")
const [results, setResults] = useState([]);
useEffect(() => {
let isMounted = true;
onSnapshot(colRef, (snapshot) => {
if (isMounted) {
const results= snapshot.docs.map((doc) => {return {...doc.data(), id: doc.id}});
setResults(results)
}
});
return () => { isMounted = false };
}, []);
This way your component'll listen to updates everytime the data changes, after that you can personalize it using querys but i wanted to show you a simple example so it's easy to understand.
I had the same problem, unfortunately, the above didn't help me. in my case I was actually importing form functions and types from '#firebase/firestore' and others from 'firebase/firestore'... this was done by autoImport. the moment I made all of them get the types and functions from the same place it worked instantly
These kind of errors occur usually when the functions aren't used the way they're supposed to. I can't really tell where the problem comes from in your code but you may try the getDocs method instead and a state variable to store your values
try this code.
const [Results, setResults] = useState([]);
useEffect(() => {
const FetchedPosts = async () => {
const querySnapshot = await getDocs(
collection(db, 'posts'),
orderBy("createdAt", "desc")
);
querySnapshot.forEach((doc) => {
setResults((prevState) => [...prevState, doc.data()]);
});
};
FetchedPosts();
}, []);

React-Native Firestore - Get user info for a comment section

I'm building an app using react-native and react-native-firebase and i'm running into an issue while trying to implement a comment section.
My tree of data is currently like that :
collection(comments)/doc(currentUser.uid)/collection(userComments)/doc(commentCreatorID)
Within this doc commentCreatorID there is all the data i need. So basically the content, a timestamp...
For this part everything works perfectly but in order to havethe commentCreator's infos stick with his post, i need to grab them somewhere else.
The way i do that is taking the doc(commentCreatorID), as it is the uid of this user and ask firestore to give me the data from the document with this same id within my "users" collection.
Here is my code :
const [comments, setComments] = useState([])
const [commentsReady, setCommentsReady] = useState([])
useEffect(() => {
setComments([])
setLoading(true)
firestore()
.collection('comments')
.doc(auth().currentUser.uid)
.collection('userComments')
.get()
.then((snapshot) => {
let comments = snapshot.docs.map(doc => {
const data = doc.data()
const id = doc.id
return {id, ...data}
})
setComments(comments)
})
.then(() => {
comments.forEach(comment => {
firestore()
.collection("users")
.doc(comment.id)
.get()
.then((snapshot) => {
const data = snapshot.data()
setCommentsReady({comments, ...data})
})
})
})
console.log(commentsReady)
setLoading(false)
}, [handleScroll4])
This doesn't seem to works well as for now. My log throw an empty array right into my face..
I'm grabbing each comment correctly tho and even each user's data corresponding to their uids.
I can log them once ForEach have been done.
But for some reason i can't have them set to my state commentsReady.
Did i miss something ?
Thanks for your time
The setters that the useState function returns are async. Copying data from one state to another is also an antipattern. Try using effects.
const TT = () => {
const [comments, setComments] = useState([]);
const [userInfos, setUserInfos] = useState([]);
const commentsView = comments.map(comment => {
// Reactively merge each comment with the appropriate user info
});
useEffect(() => {
firestore()
.collection('comments')
.doc(auth().currentUser.uid)
.collection('userComments')
.get()
.then((snapshot) => {
let comments = snapshot.docs.map(doc => {
const data = doc.data()
const id = doc.id
return {id, ...data}
});
setComments(comments);
});
}, []);
useEffect(async () => {
// Maybe keep a cache of fetched user datas, but not sure how this is architected
const snapshots = await Promise.all(comments.map(comment => {
return firestore()
.collection("users")
.doc(comment.id)
.get();
}));
setUserInfos(snapshots.map(snap => snap.data()));
}, [comments]);
};

Firestore orderBy Timestamp DESC

I'm trying to display the data from Firestore order by timestamp descending order, I follow the documentation but it seems that I did something wrong.
This is my try:
const outputSnapShot = {};
this.subscribe = firebase
.firestore()
.collection('orders')
.where('restaurant_code', '==', this.state.restaurantCode)
.orderBy('timestamp', 'desc')
.onSnapshot((doc) => {
doc.docs.map(function(documentSnapshot) {
return (outputSnapShot[documentSnapshot.id] = documentSnapshot.data());
});
if (this._isMounted) {
this.setState({ dataSource: Object.entries(outputSnapShot) });
}
});
the result from previous code is the data order by id ASC , Also I finish the INDEXING from Firebase console like so:
I hope I explained the issue clearly.
Thanks
With a help by my friend, we came with this solution and made the code work as we expected:
Going to share this:
this.subscribe = firebase
.firestore()
.collection('orders')
.where('restaurant_code', '==', this.state.restaurantCode)
.orderBy('timestamp', 'desc')
.onSnapshot((docSnapshot) => {
const dataSource = [];
docSnapshot.forEach((doc) => {
dataSource.push(doc.data());
});
if (this._isMounted) {
this.setState({ dataSource });
}
});
I have faced the same problem, in my case the following way worked for me
firebase.initializeApp(firebaseConfig);
var db = firebase.firestore();
var docRef = db.collection('Users').doc('001').collection('Data').orderBy("Date", "desc")
...

Update data using firestore cloud function

I need help, i'm trying to update my comments collections using cloud function, but my code doesn't seem to work. My function succesfully run but doesn't update my avatarUrl when my userPhotoUrl is update
Here the whole path of the collection that i want to update : "/comments/{postId}/comments/{commentId}"
my firestore collection
exports.onUpdateUser2 = functions.firestore
.document("/users/{userId}")
.onUpdate(async (change, context) => {
const userUpdate = change.after.data();
const userId = context.params.userId;
const newPhotoUrl = userUpdate.photoUrl;
console.log("userId",userId);
console.log("newPhotoUrl",newPhotoUrl);
const querySnapshot = await admin.firestore().collection("comments").get();
querySnapshot.forEach(doc => {
console.log("doc",doc.data());
const postId = doc.id;
const comments = admin.firestore().collection("comments").doc(postId).collection("comments").where("userId","==",userId).get();
comments.forEach(doc2 => {
return doc2.ref.update({avatarUrl: newPhotoUrl});
});
});
});
Thank you,
UPDATE
I try to change the code, by using then to deal with these various promises but i don't really know why commentsRef.get() seem to return me empty querySnapshots, because the comments collections in my firestore database have multiple documents where in each documents there is a another comments collections where in this seconds comments collections there is a bunch of documents containing data. With this whole path i don't know how to iterate until being in the documents containing the data that i need to update. Can someone help me please ?
exports.onUpdateUserUpdateComments = functions.firestore
.document("/users/{userId}")
.onUpdate(async (change, context) => {
const userUpdate = change.after.data();
const userId = context.params.userId;
const newPhotoUrl = userUpdate.photoUrl;
console.log("userId",userId);
console.log("newPhotoUrl",newPhotoUrl);
const commentsRef= admin.firestore().collection("comments");
return commentsRef.get().then(querySnapshot => {
return querySnapshot.forEach(doc => {
return admin
.firestore()
.collection("comments")
.doc(postId)
.collection("comments")
.where("userId", "==", userId)
.get()
.then(doc => {
if (doc.exists) {
doc.ref.update({avatarUrl: newPhotoUrl});
}
return console.log("The function has been run.");
});
});
});
});
Without trying it, it should be something like this:
return admin.firestore().collection("comments")
.doc(postId)
.where("userId", "==", userId)
.get()
.then(doc => {
if (doc.exists) {
doc.ref.update({avatarUrl: newPhotoUrl});
}
return console.log("The function has been run.");
});
Regardless, following Doug Stevenson's advice, you shouldn't start learning JS in Cloud Functions, as those nested loops are a bit strange and you may lack a good starting point for learning.

Categories

Resources