Update data using firestore cloud function - javascript

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.

Related

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

Firebase ver9 adjustment of snapshop/sub collection in React

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 !

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

Firebase Cloud Firestore Read-Write Data

i am trying to signup and save user info into firestore. Save operation is fine but i want to search that info but nothing happening. Here is my code
Signup
firestore
.collection("users")
.doc(user.userId)
.collection("profile")
.add({ ...user })
.then(() => {
auth.onAuthStateChanged((u) => {
if (u) {
u.updateProfile({
displayName: user.displayName,
});
}
});
});
Fetch All users data
firestore
.collection("users")
.get()
.then(function (querySnapshot) {
querySnapshot.forEach(function (doc) {
//doc.data() is never undefined for query doc snapshots
console.log(doc.id, " => ", doc.data());
});
});
You should be able to achieve by using a similar code as the below one. It very similar to yours, but with some differences, where we separate the referencing to the database and let the querySnapshot iterates by itself, so the data can be returned. I usually use this format to return data from collections.
var db = admin.firestore()
var usersReference = db.collection("users");
usersReference.get().then((querySnapshot) => {
querySnapshot.forEach((userDoc) => {
console.log(userDoc.id)
var userDocData = userDoc.data()
console.dir(userDocData)
})
})
This should work, so, in case it doesn't return anything, probably your saving opearation is not working properly. This will return both the user's id and the whole data from it.

Query current user .once('value') in Firestore

I am transitioning a Firebase real-time database to a Firebase Firestore database but am having trouble finding the appropriate reference to query the current user.
onAuthUserListener = (next, fallback) =>
this.auth.onAuthStateChanged(authUser => {
if (authUser) {
this.user(authUser.uid)
.once('value')
.then(snapshot => {
const dbUser = snapshot.val();
// default empty roles
if (!dbUser.roles) {
dbUser.roles = [];
}
// merge auth and db user
authUser = {
uid: authUser.uid,
email: authUser.email,
emailVerified: authUser.emailVerified,
providerData: authUser.providerData,
...dbUser,
};
next(authUser);
});
} else {
fallback();
}
});
Most specifically, what would be the replacement for once('value') and snapshot.val();?
I had thought that
.onSnapshot(snapshot => {
const dbUser = snapshot.val();
...
The equivalent of once('value' in Firestore is called get(), and the equivalent of val() is data(). Calling get() returns a promise, so:
.get().then(snapshot => {
const dbUser = snapshot.data();
...
If you have a collection of users, where the profile of each user is stored within a document with their UID as its ID, you can load that with:
firebase.firestore().collection('users').doc(authUser.uid)
.get()
.then(snapshot => {
const dbUser = snapshot.val();
Note that this is pretty well covered in the documentation on getting data, so I'd recommend spending some time there and potentially taking the Cloud Firestore codelab.

Categories

Resources