0

I have the following schema defined in two files.

faultreport.js:

var mongoose = require('mongoose');

var Schema = mongoose.Schema;

var FaultReportSchema = new Schema(
  {
    reporter: {type: String, required: true, max: 128},
    comment: [{type: Schema.ObjectId, ref: 'Comment'}],
    status: {type: String, default: 'Reported', max: 64},
    datetime: {type: Date, required: true},
  }
);

module.exports = mongoose.model('FaultReport', FaultReportSchema);

comment.js

var mongoose = require('mongoose');

var Schema = mongoose.Schema;

var CommentSchema = new Schema(
  {
    commenter: {type: String, required: true, max: 128},
    comment: {type: String, required: true, max: 1024},
    datetime: {type: Date, required: true},
  }
);

module.exports = mongoose.model('Comment', CommentSchema);

My idea is that each FaultReport is associated with one Comment on creation, but that further Comments can be added later. I would like to build a express route that can be used to list all of the FaultReports, including the comment string within the associated Comment.

I'm trying to do it like this.

router.get('/list_all', function(req, res, next) {
  FaultReport.find(function(err, reports) {
    if (err) return console.error(err);
    var data = [];
    for (var i = 0; i < reports.length; i++) {
      console.log(reports[i]);
      data.push([reports[i].datetime, reports[i].reporter, reports[i].comment[0].comment]);
    }
    res.render('list_all', {
      title: 'Fault List',
      data: data
    });
  });
});

I am clearly misunderstanding something about the way express/mongoose work, and would very much appreciate any help or advice you can give. What am I doing wrong? What do I need to do?

smolloy
  • 308
  • 1
  • 11
  • Stop thinking in relational terms. Just embed the data here and don't bother with separate collections or even code listings. Move the `CommentSchema` into `FaultReportSchema` and replace the line to `comments: [CommentSchema]` – Neil Lunn May 18 '18 at 22:37
  • Then read: [Push items into mongo array via mongoose](https://stackoverflow.com/q/33049707/2313887) and then read [Sub Docs](http://mongoosejs.com/docs/documents.html) in the mongoose documentation. – Neil Lunn May 18 '18 at 22:39
  • Round it all out with [Mongoose populate vs object nesting](https://stackoverflow.com/q/24096546/2313887) and then you might begin to get a better understanding. But the general case here is nothing you are presenting justifies a referenced model, and therefore embedding should always be the first thing you consider. Not using a traditional RDBMS it is "always" the first thing to consider, and the most simple concept to grasp once you get used to it. – Neil Lunn May 18 '18 at 22:42

1 Answers1

0

Thanks to Neil Lunn's comments, I figured out my misunderstanding of how MongoDB and Mongoose work.

I've got rid of comment.js, and moved that code to faultreport.js, which now looks like this:

var mongoose = require('mongoose');

var Schema = mongoose.Schema;

var CommentSchema = new Schema(
  {
    commenter: {type: String, required: true, max: 128},
    comment: {type: String, required: true, max: 1024},
    datetime: {type: Date, required: true},
  }
);

CommentSchema.methods.getCommenter = function() {
  return this.commenter;
}

CommentSchema.methods.getComment = function() {
  return this.comment;
}

CommentSchema.methods.getDateTime = function() {
  return this.datetime;
}

var FaultReportSchema = new Schema(
  {
    reporter: {type: String, required: true, max: 128},
    comment: [CommentSchema],
    status: {type: String, default: 'Reported', max: 64},
    datetime: {type: Date, required: true},
  }
);

FaultReportSchema.methods.getReporter = function () {
  return this.reporter;
}

FaultReportSchema.methods.getCommentId = function () {
  return this.comment;
}

FaultReportSchema.methods.getStatus = function () {
  return this.status;
}

FaultReportSchema.methods.getDateTime = function () {
  return this.datetime;
}

module.exports = {
  'FaultReport': mongoose.model('FaultReport', FaultReportSchema),
  'FaultComment': mongoose.model('FaultComment', CommentSchema)
};

The Express router for this looks like the following:

router.get('/list_all', function(req, res, next) {
  FaultReport.find(function(err, reports) {
    if (err) return console.error(err);
    var data = [];
    for (var i = 0; i < reports.length; i++) {
      console.log(reports[i]);
      data.push([reports[i].datetime, reports[i].reporter, reports[i].comment[0].getComment()]);
    }
    res.render('list_all', {
      title: 'Fault List',
      data: data
    });
  });
});

Although I'm sure that there are better ways to do this, at least I have an answer to my question :)

Since this was due to Neil Lunn's comment, I would like him to get the credit, but I'm not sure of the etiquette here. Should I accept my own answer?

smolloy
  • 308
  • 1
  • 11