我可以将对象数组发送到控制器中的视图,并与 node/express/mongoose 中的 mongodb 对象相关联吗?

Can I send an array of objects to the view, in the controller, associated with a mongodb object in node/ express/ mongoose?

我一直在关注 MDN 站点上的 Node/express/mongoose 教程。很多人可能很熟悉,但我还是会把代码放下。我想要做的是创建一个类似于 book_list 页面的视图,但是,我希望能够随每本书一起发送书籍实例(详情将在后面)。换句话说,我希望能够将每本书的 BookInstances 作为列表页面上书籍对象的一部分——它主要用于计数(或长度),但我也希望以其他方式使用它。

图书模型

var mongoose = require('mongoose');

var Schema = mongoose.Schema;

var BookSchema = new Schema({
title: {type: String, required: true},
author: { type: Schema.ObjectId, ref: 'Author', required: true },
summary: {type: String, required: true},
isbn: {type: String, required: true},
genre: [{ type: Schema.ObjectId, ref: 'Genre' }]
});

// Virtual for this book instance URL.
BookSchema
.virtual('url')
.get(function () {
  return '/catalog/book/'+this._id;
});

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

模型的 BookInstance 架构部分:

var BookInstanceSchema = new Schema(
{
  book: { type: Schema.Types.ObjectId, ref: 'Book', required: true },//reference to the associated book
  imprint: { type: String, required: true },
  status: { type: String, required: true, enum: ['Available', 'Maintenance', 'Loaned', 'Reserved'], default: 'Maintenance' },
  due_back: { type: Date, default: Date.now }
 }
);

book_list 控制器:

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

Book.find({}, 'title author')
  .populate('author')
  .exec(function (err, list_books) {
    if (err) { return next(err); }
    //Successful, so render
    res.render('book_list', { title: 'Book List', book_list: list_books });
  });

};

图书详情控制器:

// Display detail page for a specific book.
exports.book_detail = function(req, res, next) {

async.parallel({
    book: function(callback) {

        Book.findById(req.params.id)
          .populate('author')
          .populate('genre')
          .exec(callback);
    },
    book_instance: function(callback) {

      BookInstance.find({ 'book': req.params.id })
      .exec(callback);
    },
}, function(err, results) {
    if (err) { return next(err); }
    if (results.book==null) { // No results.
        var err = new Error('Book not found');
        err.status = 404;
        return next(err);
    }
    // Successful, so render.
    res.render('book_detail', { title: 'Book Detail', book: results.book, 
book_instances: results.book_instance } );
  });

   };

我觉得这一定是可以用 populate 完成的事情,但我还没有做到这一点。我设法使书籍实例对象出现在每个书籍项目的列表中的唯一方法是将所有书籍实例发送到视图。从那里我使用 foreach 循环,然后使用 IF 语句来获取每本书的书籍实例。它看起来真的很难看,我相信一定有其他方法可以做到这一点。我习惯了 asp.net mvc - 因为你使用了一个虚拟对象。我不确定我是否应该在这里修改模型或控制器。我可能还想传入一个列表中包含列表的更复杂的模型。

我注意到类型实际上保存在书籍文档中,与书籍实例不同 - 因此书籍详细信息控制器中的行:

  book_instance: function(callback) {
  BookInstance.find({ 'book': req.params.id })
  .exec(callback);
},

下面我展示了我所做的。我也可以将其作为控制器中的对象来完成,但这就是我现在所拥有的:

图书管理员:

exports.book_list = function (req, res, next) {

async.parallel({
    books: function (callback) {
        Book.find()
            .exec(callback)
    },
    bookinstances: function (callback) {
        BookInstance.find()
            .exec(callback)
    },
}, function (err, results) {
    if (err) { return next(err); } // Error in API usage.
    // Successful, so render.
    res.render('book_list', { title: 'Book Detail', books: results.books, 
bookinstances: results.bookinstances });
});
};

book_list.pug代码:

extends layout

block content
 h1= title

table.table
th Book
th BookInstance Count
th 
//- above th is for buttons only (no title)
each book in books
  - var instCount = 0
  each bookinstance in bookinstances
    if book._id.toString() === bookinstance.book.toString()
      - instCount++
  tr 
    td 
      a(href=book.url) #{book.title}
    td #{instCount}

    td
      a.btn.btn-sm.btn-primary(href=book.url+'/update') Update
      if !instCount
        a.btn.btn-sm.btn-danger(href=book.url+'/delete') Delete

else
  li There are no books.

页面显示为:

问题被确定为我试图将 MongoDb 用作关系数据库而不是文档类型。这个问题的解决方法是像 genre:

一样,在 Book 文档中使用 BookInstances 数组
var BookSchema = new Schema({
title: {type: String, required: true},
author: { type: Schema.ObjectId, ref: 'Author', required: true },
summary: {type: String, required: true},
isbn: {type: String, required: true},
genre: [{ type: Schema.ObjectId, ref: 'Genre' }],
bookInstances: [{ type: Schema.ObjectId, ref: 'BookInstance' }]
});

所有细节仍然可以保留在 BookInstance 文档中,因为 _id 是 Book 文档中所需的全部内容。每当添加 BookInstance 时,它​​都可以被推送到 Book/BookInstances 数组中(这 post 有帮助:)。这也意味着需要从数组中删除(拉出)BookInstance 以及包含其详细信息的文档。

现在可以正常使用mongoose populate()了。