首页 > 解决方案 > 我可以将一组对象发送到控制器中的视图,与 node/express/mongoose 中的 mongodb 对象相关联吗?

问题描述

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

书籍模型

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 Schema 部分:

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 } );
  });

   };

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

我注意到与 bookinstances 不同,类型实际上保存到 book 文档中 - 因此 book detail 控制器中的行:

  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.

页面显示为:

在此处输入图像描述

标签: node.jsmongodbexpressmongoosemean-stack

解决方案


问题被确定为我试图将 MongoDb 用作关系数据库而不是文档类型。这个问题的解决方案是在 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 数组中(这篇文章有帮助:通过 mongoose 将项目推送到 mongo 数组中)。这也意味着 BookInstance 需要从数组以及包含其详细信息的文档中删除(拉出)。

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


推荐阅读