In Firebase I have two Documents. one is "users" and "posts".
Inside posts, I have added an id equal to the "users" collection id.
What I'm trying to achieve is when I'm getting posts I need to get post-added user data.
I'm getting all the posts but I cannot get related user data. Can anyone help me do this?
import {
collection,
query,
onSnapshot,
orderBy,
doc,
getDoc,
} from "firebase/firestore";
import { db } from "../../FireBaseConfig";
export default function Home() {
const [posts, setPosts] = useState();
const getPostUser = async (userID) => {
try {
const userQuery = doc(db, "users", userID);
const userRef = await getDoc(userQuery);
const userData = userRef.data();
return userData;
} catch (err) {
console.log(err);
}
};
useEffect(() => {
const getPosts = async () => {
try {
const q = query(collection(db, "posts"), orderBy("statusDate", "desc"));
const unsubscribe = onSnapshot(q, (querySnapshot) => {
let posts_arr = [];
let adsfadsfad = "";
querySnapshot.forEach(async (item, index, array) => {
getPostUser(item.data().id)
.then((res) => {
adsfadsfad.push(res);
})
.catch((err) => {
console.log(err);
});
console.log(adsfadsfad);
posts_arr.push(
<div className="home__posts--post" key={item.id}>
<div className="home__posts--post-user flex items-center">
{/* <img
src={abc["avatar"]}
alt={abc["avatar"]}
className="w-[50px] h-[50px] rounded-full"
/>
<h4>{abc["avatar"]}</h4> */}
{/* {asdasd} */}
</div>
<div>
{item.data().statusImage && (
<img
src={item.data().statusImage}
alt={item.data().status}
/>
)}
</div>
</div>
);
});
setPosts(posts_arr);
});
} catch (err) {
console.log(err);
}
};
getPosts();
}, []);
return (
<div className="home p-4 max-w-screen-sm mx-auto">
<div className="home__posts">{posts}</div>
</div>
);
}
CodePudding user response:
Your code also queries for user data for every post. In case all the posts returned by first query are posted by same person, it'll be redundant. Also the getDoc()
(getPostUser()
) returns a Promise
so you need to handle that as well. Try refactoring the code as shown below:
useEffect(() => {
const getPosts = async () => {
const q = query(collection(db, "posts"), orderBy("statusDate", "desc"));
const unsubscribe = onSnapshot(q, async (querySnapshot) => {
const posts = querySnapshot.docs.map((doc) => ({
id: doc.id,
...doc.data(),
}));
// Get an array of unique user IDs from all posts
const userIds = [...new Set(posts.map((post) => post.userId))];
// Fetch documents of those users only
const userPromises = userIds.map((userId) =>
getDoc(doc(db, "users", userId))
);
const userDocs = await Promise.all(userPromises);
// Record<string, UserDocumenData>
const users = userDocs.reduce((acc, userDoc) => {
acc[userDoc.id] = userDoc.data();
return acc;
}, {});
// use "posts" array and "users" object to render your UI
// You can get user info as shown below
// const postUser = users[posts[0].userId]
});
};
getPosts();
}, []);
If you want to, you can also additionally remove some userId
from the second query in case their data has been fetched already.