Search code examples
javascriptnode.jsexpresspug

Referenced Objects and Virtual getters returning undefined in pug layout file, but queried successfully from database


My problem is two-fold, but I think they are both caused by the same issue: my Schema definition and/or Model creation.

I am following this MDN Nodejs tutorial and i cannot figure out:

  1. Why my referenced objects are returning undefined in my layout file, yet I have confirmed that the data is being correctly inserted and queried(as far as i can tell).

  2. My virtual id getter is not working.

Schema Definition:

book.js italize

const mongoose = require('mongoose');
const Schema = mongoose.Schema;

const BookSchema = new Schema({

  title: {type: String, required: true},
  author: {type: Schema.Types.ObjectId, ref: 'Author', required: true},
  summary: {type: String, required: true},
  isbn: {type:String, required: true},
  genre: [{type: Schema.Types.ObjectId, ref: 'Genre'}]

});

//this doesnt seem to be working. returns undefined on the
//object in layout file
BookSchema
.virtual('url')
.get(() => {
  return '/catalog/book/' + this._id;
});

module.exports = mongoose.model('Book', BookSchema);

author.js italize

const mongoose = require('mongoose');
const Schema = mongoose.Schema;

const AuthorSchema = new Schema({

  first_name: {type: String, required: true, max: 100},
  family_name: {type: String, required: true, max: 100},
  date_of_birth: {type: Date},
  date_of_death: {type: Date}

});

//Virtuals

AuthorSchema.virtual('name')
.get(() => {
  return this.family_name + ', ' + this.first_name;
});

//create virtual absolute url to obtain instance of this model
AuthorSchema.virtual('url')
.get(() => {
  return '/catalog/author/' + this._id;
});

module.exports = mongoose.model('Author', AuthorSchema);

Model Creation:

function authorCreate(first_name, family_name, d_birth, d_death, cb) {
  authordetail = {first_name:first_name , family_name: family_name }
  if (d_birth != false) authordetail.date_of_birth = d_birth
  if (d_death != false) authordetail.date_of_death = d_death

  var author = new Author(authordetail);

  author.save(function (err) {
    if (err) {
      cb(err, null)
      return
    }
    console.log('New Author: ' + author);
    authors.push(author._id)
    cb(null, author)
  }  );
}

function bookCreate(title, summary, isbn, author, genre, cb) {
  bookdetail = {
    title: title,
    summary: summary,
    author: author,
    isbn: isbn
  }
  if (genre != false) bookdetail.genre = genre

  var book = new Book(bookdetail);
  book.save(function (err) {
    if (err) {
      cb(err, null)
      return
    }
    console.log('New Book: ' + book);
    books.push(book._id)
    cb(null, book)
  }  );
}

controller.js:

// Display list of all books.
exports.book_list = function(req, res) {

  Book.find({})
  .populate('author')//this seems to work
  .exec(function (err, list_books) {
    if (err) { return next(err); }
    //Successful, so render
    for(var b in list_books){
      console.log('author id: ' + list_books[b].author._id);//as evidenced here

    }

    //but the author object is undefined when rendered
    res.render('book_list', { title: 'Book List', book_list: list_books });

  });

};

layout.pug:

extends layout

block content
  h1= title
//url and author undefined here
  ul
    each book in book_list
      li
        a(href=book.url) #{book.title}
        |  #{book.author.name}

    else
      li There are no books.

Screenshot:

This is the end result

Tools:

  • Node + Express js

  • Pug

  • mLab free tier

I am completely new to Mongoose DB & Pug and know only as much as the primers in the tutorial have taught and explicitly pointed to as further reading.

Let me know if you need any more information. Thanks


Solution

  • I looks like my problem was usage of fat arrow functions. Changing those to regular function() syntax fixed the issue.

    This answer confirmed that its a support issue in nodejs.