为啥 MongoDB 填充方法在此应用程序中失败?

Posted

技术标签:

【中文标题】为啥 MongoDB 填充方法在此应用程序中失败?【英文标题】:Why does MongoDB populate method fail in this application?为什么 MongoDB 填充方法在此应用程序中失败? 【发布时间】:2020-07-27 14:20:33 【问题描述】:

我正在使用Express、EJS 和 MongoDB 开发 blogging application(单击链接以查看 GitHub 存储库)。

我有 PostsPost Categories,每个都在自己的集合中。

类别架构:

const mongoose = require('mongoose');

const categorySchema = new mongoose.Schema(
    cat_name: 
        type: String,
        required: true
    ,
    updated_at: 
        type: Date,
        default: Date.now()
    ,
    created_at: 
        type: Date,
        default: Date.now()
    
);

module.exports = mongoose.model('Category', categorySchema);

帖子架构:

const mongoose = require('mongoose');

const postSchema = new mongoose.Schema(
    title: 
        type: String,
        required: true
    ,
    short_description: 
        type: String,
        required: true
    ,
    full_text: 
        type: String,
        required: true
    ,
    category: 
        type: mongoose.Schema.Types.ObjectId,
        ref: 'category'
    ,
    post_image: 
        type: String,
        required: false
    ,
    updated_at: 
        type: Date,
        default: Date.now()
    ,
    created_at: 
        type: Date,
        default: Date.now()
    
);

module.exports = mongoose.model('Post', postSchema);

显示帖子的控制器方法

exports.displayDashboard = (req, res, next) => 
    const posts = Post.find(, (err, posts) => 
        if(err)
            console.log('Error: ', err);
         else 
            res.render('admin/index', 
              layout: 'admin/layout',
              website_name: 'MEAN Blog',
              page_heading: 'Dashboard',
              posts: posts
            );
        
    ).populate( path: 'category', model: Category )
;

如果在视图中我有:

<table class="table table-striped table-sm mb-0">
    <thead>
        <tr class="d-flex">
            <th class="col-1 pl-2">#</th>
            <th class="col-2">Title</th>
            <th class="col-2">Category</th>
            <th class="col-2">Created</th>
            <th class="col-2">Updated</th>
            <th class="col-3 pr-2 text-right">Actions</th>
        </tr>
    </thead>
    <tbody>
        <% if (posts)  %>
            <% posts.forEach(function(post, index)  %>
                <tr data-id="<%= post._id %>" class="d-flex">
                    <td class="col-1 pl-2">
                        <%= index + 1 %>
                    </td>
                    <td class="col-2">
                        <a href="/<%= post._id %>" class="text-dark">
                            <%= post.title %>
                        </a>
                    </td>
                    <td class="col-2">
                        <%= post.category %>
                    </td>
                    <td class="col-2">
                        <%= post.created_at.toDateString(); %>
                    </td>
                    <td class="col-2">
                        <%= post.updated_at.toDateString(); %>
                    </td>
                    <td class="col-3 text-right pr-2">
                        <div class="btn-group">
                            <a href="../dashboard/post/edit/<%= post._id %>" class="btn btn-sm btn-success">Edit</a>
                            <a href="#" class="btn btn-sm btn-danger delete-post" data-id="<%= post._id %>">Delete</a>
                        </div>
                    </td>
                </tr>
                <% ); %>
                <%  else  %>
                <tr>
                  <td colspan="5">There are no posts</td>
                </tr>
                <%  %>
    </tbody>
</table>

一个对象显示在 Category 列(posts 表的):

然而,我尝试使用 &lt;%= post.category.cat_name %&gt; 显示 类别名称 我收到此错误:

Cannot read property 'cat_name' of null

我做错了什么?

【问题讨论】:

首先,猫鼬将您的架构在内部转换为小写字母(例如“类别”=> 类别)。因此,postSchema 中的类别应引用“类别”,因此请尝试。你有没有测试过post._id之外的其他字段是否可以成功渲染? @rags2riches 我试过了。 t 不是那样的。 【参考方案1】:

我发现了问题所在:我删除了一个之前分配给帖子的类别。修复很简单(在视图中):

<%= post.category != null ? post.category.cat_name : 'No category assigned' %>

而不是

<%= post.category.cat_name %>

非常感谢参与提供帮助的所有人。

【讨论】:

【参考方案2】:

您可以遵循此准则

您的型号名称是:类别

// Please Define post Schema
category: 
        type: mongoose.Schema.Types.ObjectId,
        ref: 'Category'
    

// Your Controller
exports.displayDashboard =async (req, res, next) => 
    const posts =await Post.find().populate('category')
    if(posts)
      res.render('admin/index', 
              layout: 'admin/layout',
              website_name: 'MEAN Blog',
              page_heading: 'Dashboard',
              posts: posts
            )


【讨论】:

你可以使用异步等待。 我该怎么做? 我发现了问题并在其中发布了 solution。感谢您的帮助。【参考方案3】:

使用 async/await 运算符,因为 populate 返回一个 Query,可以等待。更多信息和代码示例可以在Mongoose官方的documentation中找到。

async function yourAwesomeFunction (req, res, next) 
   try 
      const posts = await Post
         .find( )
         .populate( path: 'category' );

      res.render('path/to/layout',  posts: posts );
    catch (e) 
      // TODO: handle possible errors...
   
;

【讨论】:

我发现了问题并在其中发布了 solution。如果有兴趣,请检查它。谢谢你帮助我。

以上是关于为啥 MongoDB 填充方法在此应用程序中失败?的主要内容,如果未能解决你的问题,请参考以下文章

为啥游戏安装失败

为啥以下代码编译失败(C++ lambda问题)

调用 findOne 并填充时,转换为 objectid 的值失败

是否有一种简单的方法可以在此 Access 数据库架构中填充下拉列表?

插入时在 MongoDB 中自动填充日期

为啥在 mongoose 中需要 execPopulate 方法来填充现有文档?