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

Posted

技术标签:

【中文标题】我可以将一组对象发送到控制器中的视图,与 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? 【发布时间】:2019-07-26 19:55:26 【问题描述】:

我一直在关注 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  );
  );

   ;

我有一种感觉,它一定是可以用 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.

页面显示为:

【问题讨论】:

我觉得有必要在这里提出建设性的批评。您一直在谈论 BookInstance 并将其与预订“联系起来”。但是您的问题没有任何部分显示BookInstance 的任何结构,或者可能更重要的是向我们展示了BookBookInstance 的一些数据。或者真正重要的是,展示了可以从与您要实现的目标相关的所述数据中获得的某种示例输出。您可以放弃 90% 的“背景故事”,专注于呈现问题以及数据和相关代码/结构以解决问题。 我想要视图中每本书的 BookInstances 列表。我将在问题中包含 BookInstance 模型。这显然不像我想象的那么明显。 【参考方案1】:

问题被确定为我试图将 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 数组中(这篇文章有帮助:Push items into mongo array via mongoose)。这也意味着 BookInstance 需要从数组以及包含其详细信息的文档中删除(拉出)。

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

【讨论】:

以上是关于我可以将一组对象发送到控制器中的视图,与 node/express/mongoose 中的 mongodb 对象相关联吗?的主要内容,如果未能解决你的问题,请参考以下文章

php 一个用数据呈现php文件的函数。允许模板化,然后将一组数据发送到视图中。

如何将一组 UIButtons 添加到 UIStackview 上?

如何将一组结构从 web3js 发送到 Solidity 合约?

将一组按钮添加到特定的子视图

将 collectionView 数据发送到另一个视图控制器中的网点

Spring将对象从视图发送到控制器