【问题标题】:Mongoose/Node How to access DB in directly in EJS fileMongoose/Node 如何在 EJS 文件中直接访问数据库
【发布时间】:2018-12-23 07:00:24
【问题描述】:

我想在我的 EJS 头文件中访问我的数据库,这是一个添加到每个页面的部分。

我有一个名为 Category 的架构,我想从 db 中动态获取标题中的类别名称。

我正在尝试运行以下命令:

<%    Category.find({}, name, function(err, names) {    %>
                        <%        if(err) { console.log(err); }                 %>
                        <%        console.log("Names: " + names);               %>
                        <%    });                                               %>

当然,头ejs文件无权访问Category。

我通常知道要在 ejs 文件中访问我的数据库我在路由中查询数据库,然后将数据传递给 ejs,但在这里,因为它是将添加到每个页面的标题,我真的不能这样做在路线中进行此操作,除非我在每条路线上都这样做,这似乎是个好主意。

如何在此处获取这些数据?

谢谢

【问题讨论】:

    标签: node.js mongodb mongoose ejs


    【解决方案1】:

    不应直接在视图中执行数据库请求。这是 MV* 模式背后的关注点分离原则所规定的。

    Express 路由处理程序充当 MVC 控制器,它们的目的是将数据从模型提供给视图。

    Mongoose 支持 Promise,因此使用基于回调的 API 只会让一切变得复杂。像这样的公共数据可以作为一个单独的函数提供,该函数返回一个数据的承诺,例如:

    function getPageData() { ... }
    
    async function routeHandler(req, res, next) {
      try {
        const pageData = await getPageData();
        res.render('index', {
          ...pageData,
          / * etc */
        });
      } catch (err) {
        next(err);
      }
    };
    

    routeHandler 本身可以重构为接受视图、视图变量、reqresnext 的辅助函数。

    另一种方法是使用附加中间件使页面数据在所有或大多数视图中全局可用,如this related question 中所述,例如:

    app.use(async function (req, res, next) {
      try {
        const pageData = await getPageData();
        Object.assign(res.locals, pageData);
        next();
      } catch (err) {
        next(err);
      }
    });
    

    【讨论】:

    • 您好,感谢您的出色回答。我是一个初学者,所以我一直在尝试了解答案是如何工作的,第一种方法是我将 routehandler 作为中间件传递到我的所有路线中,对吗?第二个我试图了解它何时运行,难道 app.use 只在应用程序加载时运行一次???我的数据可能会在途中发生变化,所以我需要在每次提出请求时检查它。但是后来我看到我在另一个线程上看到的 res.locals 必须分配给每个请求,所以它似乎运行得更多?我也不是很清楚,还有为什么我们要使用 Object.assign 将 pageData 保存到 res.locals 中?
    • routeHandler 应该作为路由处理程序传递给使用 index 视图的路由,例如app.get('/', routeHandler) - 或更多,如果它是单页应用程序。如前所述,它可以被重构为更通用。 app.use() 只运行一次,但中间件函数在每个请求上运行,这就是重点。 Object.assign 将 pageData 中的所有属性复制到 res.locals。
    • 谢谢我现在肯定得到第二个!至于第一个,数据将用于我的标题,它将具有所有页面的导航栏,因此作为部分包含在所有页面中,这就是让它变得困难的原因。为什么我将路由处理程序传递给索引文件路由?你的意思是所有的路线??
    • 我的意思是在 sn-p 1 中你需要指定视图名称。您不能将其应用于所有路由,因为 res.render 需要视图名称。您可以使用常规编程技术使这段代码干燥。无论如何,sn-p 2 都适合。
    • 知道了,谢谢 Estus 的回答和清理一切!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-18
    • 2013-11-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多