Search code examples
javascriptmongodbmongoose-schema

how can i get posts that includes an array including userId


I am trying to add a bookmark feature to my site so that the user can save the posts he wants to save, but it does not work as expected

It is assumed that when the user clicks on the bookmark button on the site, his ID is stored in the saves array, and then when the user tries to view the saved posts, every post that includes the ID of this user in the saves array is called.

When I try to fetch data from the front end I get this error "Cannot read properties of undefined (reading 'includes')"

Note: that saves is defined as an array of users id's in schema

this is my controller.js function:

 const getSavedPosts = async(req, res) => {
 try {
     const userId = req.user._id;
     const post = await Post.find();
     const savedP = await post.saves.includes(userId);
     if(savedP){
     const userSavedPost = await Post.find({userId: {$in: savedP} })
        
         res.status(200).json(userSavedPost);
         console.log(userSavedPost)
         } else {
             return;
         }

     } catch (err) {
         res.status(500).json({ error: err.message });
     }
 };

PostModel.js

import mongoose from "mongoose";
    
     const postSchema = mongoose.Schema({
         postedBy: {
             type: mongoose.Schema.Types.ObjectId,
             ref: 'User',
             required: true
         },
         text: {
             type: String,
             maxLength: 500
         },
         img: {
             type: String,
         },
         likes: {
             // array of users id's
             type: [mongoose.Schema.Types.ObjectId],
             ref: "User",
             default: []
         },
         saves: {
             // array of users id's
             type: [mongoose.Schema.Types.ObjectId],
             ref: "User",
             default: []
         },
         replies: [
             {
                 userId: {
                     type: mongoose.Schema.Types.ObjectId,
                     ref: 'User',
                     required: true
                 },
                 text: {
                     type: String,
                     required: true
                 },
                 userProfilePic: {
                     type: String,
                 },
                 username: {
                     type: String
                 }
             }
         ]
     }, {timestamps: true}
     )
    
     const Post = mongoose.model('Post', postSchema);
    
     export default Post;

Solution

  • You have made a good start but there are quite a few issues with your code. Therefore I will just give you a solution with some notes to explain them as it's easier that way.

    Update your postSchema so that the likes and saves properties are like so:

    //...
    
    likes: [{
       type: mongoose.Schema.Types.ObjectId,
       ref: "User",
       default: []
    }],
    saves: [{
       type: mongoose.Schema.Types.ObjectId,
       ref: "User",
       default: []
    }],
    
    //...
    

    Update your getSavedPosts function like so:

    const getSavedPosts = async(req, res) => {
       try {
          // Log the req.user object to make sure you have values in there.
          // In my experience it's actually req.session.user._id you need to
          // refer to if you are using sessions but maybe not.
          console.log('req.user=', req.user);
          const userId = req.user._id;
          // You can just search for the userId now in the saves array.
          // Mongoose will find all Posts that where userId appears in the saves array
          const userSavedPost = await Post.find({saves: userId });
          // Check for an empty array. length > 0 will be truthy
          if(userSavedPost.length){
             console.log(userSavedPost);
             return res.status(200).json({
                posts: userSavedPost
             });
          }else{
             return res.status(200).json({
                message: 'No posts found'
             });
          }  
       } catch(err) {
          // Log the error but don't send it back to front-end to stop leak
          // of sensitive information
          console.log(err);
          res.status(500).json({ 
             message: 'Error on server' 
          });
       }
    };