node.js – Need to populate a specific users posts on their profile (MERN stack)

I am stuck trying to do this. I have tried multiple different methods and I haven’t been able to crack this. The User should see their Posts when they open the Profile. I have added the PostSchema and User schema along with the routes and actions I have used. Please do correct me wherever I am wrong. I have also added the client side to know how I should integrate this. I am a newbie so please help!! I need to submit the project ASAP.

(Server)

PostSchema

import mongoose from 'mongoose';

const postSchema = mongoose.Schema({
    title: String,
    message: String,
    name: String,
    creator: String,
    tags: [String],
    selectedFile: String,
    likes: {
        type: [String],
        default: [],
    },
    disLikes: {
        type: [String],
        default: [],
    },
    comments: {
        type: [String],
        default: [],
    },
    createdAt: {
        type: Date,
        default: new Date()
    }, 
});

const PostMessage = mongoose.model('PostMessage', postSchema);

export default PostMessage;

UserScheme

import mongoose from 'mongoose';

const userSchema = mongoose.Schema({
    name: {type: String, required: true},
    username: {type: String, required: true},
    emailId: {type: String, required: true},
    phoneNumber: {type: String, required: true},
    password: {type: String, required: true},
    imageUrl: String,
    id: {type: String},
})

export default mongoose.model("User", userSchema);

Controllers (getUserPosts is what I am trying to use)

import mongoose  from "mongoose";
import PostMessage from "../models/postMessage.js";
import User from "../models/user.js";

export const getPosts = async (req, res) => {
    try {
        const posts = await PostMessage.find().sort({ _id: -1 });
        
        res.status(200).json({ data: posts});
    }   catch (error) {
        res.status(404).json({ message: error.message});  

    }
};
export const getPost = async (req, res) => {
    const { id } = req.params;
    try {
        const post = await PostMessage.findById(id);
        
        res.status(200).json(post);
    }   catch (error) {
        res.status(404).json({ message: error.message});  

    }
};
export const getUserPosts = async (req, res) => {
    const creator = req.userId;
    
    try {
            
        const userPosts = await PostMessage.find(creator).sort({ _id: -1 });
        res.status(200).json({data: userPosts}); 
    } catch (error) {
        console.log(error);
        res.status(500).json({ message: error });
    }
};

Routes

import express from "express";
import { getPostsBySearch, getPosts, getPost, createPost, updatePost, deletePost, likePost, disLikePost, commentPost, getUserPosts } from "../controllers/posts.js";
import auth from '../middleware/auth.js';

const router = express.Router();

router.get('/search', getPostsBySearch );
router.get("https://stackoverflow.com/", getPosts );
router.get('/:id', getPost);
router.get('/userId', auth, getUserPosts);
router.post("https://stackoverflow.com/", auth, createPost);

Client

Actions

import { FETCH_ALL, CREATE, UPDATE, DELETE, FETCH_BY_SEARCH, FETCH_POST, START_LOADING, END_LOADING, COMMENT, FETCH_USER_POSTS } from '../constants/actionTypes';
import * as api from '../api';

export const getPosts = () => async (dispatch) => {
    try {
        dispatch({ type: START_LOADING });
        const { data } = await api.fetchPosts();
        dispatch({ type: FETCH_ALL, payload: data });
        dispatch({ type: END_LOADING});
    } catch (error) {
        console.log(error);
    }
    
}
export const getPost = (id) => async (dispatch) => {
    try {
        dispatch({ type: START_LOADING });
        const { data } = await api.fetchPost(id);
        dispatch({ type: FETCH_POST, payload: data });
        dispatch({ type: END_LOADING});
    } catch (error) {
        console.log(error);
    }
    
}
export const getUserPosts = (userId) => async (dispatch) => {
    try {
        dispatch({ type: START_LOADING });
        const { data } = await api.fetchUserPosts(userId);
        dispatch({ type: FETCH_USER_POSTS, payload: data });
        dispatch({ type: END_LOADING});
    } catch (error) {
        console.log(error);
    }
    
}

API

import axios from "axios";


const API = axios.create({ baseURL: 'http://localhost:5000' });
API.interceptors.request.use((req) => {
    if(localStorage.getItem('profile')) {
        req.headers.authorization = `Bearer ${JSON.parse(localStorage.getItem('profile')).token}`;
    }

    return req;
});


export const fetchPosts = () => API.get('/posts');
export const fetchPost = (id) => API.get(`/posts/${id}`);
export const fetchPostsBySearch = (searchQuery) => API.get(`posts/search?searchQuery=${searchQuery.search || 'none' }&tags=${searchQuery.tags}`);
export const fetchUserPosts = (userId) => API.get(`posts/${userId}`);

ProfilePage (component)

import React, { useState, useEffect } from 'react';
import {makeStyles} from '@material-ui/core/styles';
import {  useLocation } from 'react-router-dom';
import { Container, AppBar, Typography, Grow, Grid, Card, Button, ListItemAvatar, ListItem, List, Paper} from '@material-ui/core';
import { useDispatch, useSelector } from "react-redux";
import UserProfile from './UserProfile';
import UserPosts from '../Posts/UserPosts';
import { getUserPosts } from '../../actions/posts';


import "../../App.css";
import ProfileData from './ProfileData';
import useStyles from "./styles";

const ProfilePage = () => {
  const [currentId, setCurrentId] = useState(null);
  const [userId, setUserId] = useState(null);
  const { post, posts, isLoading } = useSelector((state) => state.posts);
  const [user, setUser] = useState(JSON.parse(localStorage.getItem('profile')));
  useEffect(() => {
    const token = user?.token;
    setUser(JSON.parse(localStorage.getItem('profile')));
}, [location]);
  const classes = useStyles();
  const dispatch = useDispatch();
  useEffect(() => {
    dispatch(getUserPosts());
  }, [userId, dispatch]);
  
    
    return (
      <>
        <Grow in>
  
          <Container maxWidth="lg">
              <Grid contianer position= "absolute" justify="space-between" alignItems="stretch" spacing={1}>
                <Paper className={classes.card} elevation={7}>
                <ProfileData />
                </Paper>
                <div className={classes.buttons}>
                  <Button className={classes.button}>{user.result.name}'s Posts</Button>
                    
                  <Button className={classes.button}>Constests entered by {user.result.name}</Button>
                  
                </div>
                <Grid item xs={12} sm={11}>
                  <UserPosts setUserId={setUserId}/>
                </Grid>
                
  
              </Grid>
            </Container>
        </Grow>
      </>
    )
  }


export default ProfilePage

How i am populating my Feed as of now is using this on the client side. Feed

import React from "react";
import useStyles from "./styles";
import { Grid, CircularProgress } from "@material-ui/core";
import Post from './Post/Post';
import { useSelector } from "react-redux";

import { Marginer } from "../Auth/Marginer";
import Formbar from "../FormBar/FloatingButtonForm";

const Posts = ({ setCurrentId }) => {
    const {posts, isLoading} = useSelector((state) => state.posts);
    const classes = useStyles();
    
    
    if(!posts.length && !isLoading) return 'No Posts Available';
    
    return (
        isLoading ? <CircularProgress /> : (
            
            <Grid className={classes.container} container alignItems="stretch" spacing={8}>
                
                <Marginer direction="vertical" margin="75px" />
                <Formbar/>
                {posts.map((post) => (
                    <Grid key={post._id} item xs={12} sm={12} >
                        <Post post={post} setCurrentId={setCurrentId}/>

                    </Grid>
                ))}
                
            </Grid>
            
        )
    );
    
}

export default Posts;

Reducers

import { FETCH_ALL, CREATE, FETCH_POST, UPDATE, DELETE, FETCH_BY_SEARCH, START_LOADING, END_LOADING, COMMENT, FETCH_USER_POSTS } from '../constants/actionTypes';
export default (state = { isLoading: true, posts: []}, action) => {
    switch(action.type) {
        case START_LOADING:
            return {...state, isLoading: true};
        case END_LOADING:
            return {...state, isLoading: false};
        case DELETE:
            return {...state, posts: state.posts.filter((post) => post._id !== action.payload)};
        case UPDATE:
            return {...state, posts: state.posts.map((post) => post._id === action.payload._id ? action.payload : post)};
        case COMMENT:
            return {...state, 
                posts: state.posts.map((post) => {
                    if(post._id === action.payload._id) return action.payload;

                    return post;
                }),
            };
        case FETCH_ALL:
            return {
                ...state,
                posts: action.payload.data
            };
        case FETCH_USER_POSTS:
            return{...state, posts: action.payload};
        case FETCH_BY_SEARCH:
            return {...state, posts: action.payload };
        case FETCH_POST:
            return {...state, post: action.payload};
        case CREATE:
            return {...state, posts: [...state.posts, action.payload]};
        default:
            return state; 
    }

}

Leave a Comment