Cannot read property 'name' of undefined - mongoose, express, nodeJS, ejs

Viewed 272

How would I go about getting the name of the user from an object ID? Im currently using populate to pull the user data from one schema to another and it's returning both the user ID and the name however I just want the name to show up. I have tried using post.submittedby.name in the view however I keep receiving a 'name is undefined' error. I have also tried to set it to a variable but same error.

Below is how my data is displaying on the page.

Here is how the info is showing, would like to extract just the name.

Ideally I would like it to say Posted By: user2

Documents below

Post model

const mongoose = require('mongoose');

const PostSchema = new mongoose.Schema({
    title: {
        type: String,
        required: true
    },
    body: {
        type: String,
        required: true,
    },
    date: {
        type: Date,
        default: Date.now,
        required: true,
    },
    submittedBy: {
        type: mongoose.Schema.Types.ObjectId, 
        ref: 'User',
    },
    comments: {
        type: String,
        default: 'Other info goes here',
    }
})

const Post = mongoose.model('Post', PostSchema);
module.exports = Post;

User model

const mongoose = require('mongoose');

const UserSchema = new mongoose.Schema({
    name: {
        type: String,
        required: true
    },
    email: {
        type: String,
        required: true
    },
    password: {
        type: String,
        required: true
    },
    date: {
        type: Date,
        default: Date.now
    }
});

const User = mongoose.model('User', UserSchema);
module.exports = User;

index.js

router.get('/dashboard', ensureAuthenticated, (req, res) => {
  Post.find()
    .populate({ path: 'submittedBy', select: 'name' })
    .then((result) => {
      res.render('dashboard', {
        posts: result,
        user: req.user,
      })
      
    })
    .catch((err) => {
      console.log(err)
    })

})

Home page/dashboard view.ejs

        <div class="forumView">
            <h2>All Posts</h2>

            <% if (posts.length > 0)  {%>
            <% posts.forEach(post => { %>

                <h3 class="title"> <%= post.title %></h3>
                <p class="body"> <%= post.body %> </p>
                <p class="body"> Posted by: <%= post.submittedBy %> </p>

            <% }) %>
            <% } else { %>
                <p>There are no posts to display...</p>  
                <% } %>  
        </div>
1 Answers

I think what's happening is when you pass results down to the template, those submittedBy subdocuments are converted into strings. So try this:

router.get('/dashboard', ensureAuthenticated, (req, res) => {
  Post.find()
    .populate({ path: 'submittedBy', select: 'name' })
    .lean() // <- This will give you plain JSON objects as opposed to mongoose docs.
    .then((result) => {
      result.forEach(i => i.submittedBy = i.submittedBy.name) // <- This will override the submittedBy prop with the actual name vs an object
      res.render('dashboard', {
        posts: result,
        user: req.user,
      })
      
    })
    .catch((err) => {
      console.log(err)
    })
})

After this, no changes to the template code are necessary.

Disclaimer: I have not tested this.

Related