首页 > 解决方案 > 如何将数据库查询从模型传递到 Express.js 中的控制器

问题描述

我有一个product.js执行此操作的模型文件:

const mssql = require('mssql/msnodesqlv8');

module.exports.rsProducts = function () { // update1: removed params req,res,next

        global.MYDB.connect(function (error) { // MYDB is a mssql-server database setup in app.js as a global variable
            if (error) {
                console.log(error);
                return;
            }

            global.MYDB.request().query('SELECT Top(10) * FROM [dbo].[Product]', function (err, result) {

console.log(result); // this works and i see the database recordset in the console
return(result); // this does not seem to do anything (see below)

            });

        });

我有一个名为的控制器文件index.js,它像这样调用模型:

var router = require('express').Router();
const mssql = require('mssql/msnodesqlv8');
const Offer = require('../models/product');

Offer.rsProducts(); // the console.log(result) line in the model file logs the recordset to the console

console.log(Offer.rsProducts()); // this log does not log anything which means no result is being returned from the model file to this controller

我的问题是为什么模型中的return(result)product.js没有向我的控制器返回任何内容?最终我希望控制器呈现这样的视图文件:

router.get('/', function(req, res, next) { res.render('index', { pagetitle: 'Product Name', data: Offer.rsProducts() }); });

以上永远不会奏效,因为没有任何东西来自Offers.rsProduct().

更新 1 我需要一个可扩展的答案,以便控制器可以根据需要从尽可能多的模型调用尽可能多的数据库函数。该网站的主页需要来自大约 4 种不同模型的数据库数据。真的,最终结果(我在脑海中想象)是控制器会做这样的事情(伪代码):

var router =  require('express').Router();
const Offer = require('../models/product');
const Story = require('../models/story');
const QandA = require('../models/qanda');
const Job =   require('../models/job');

router.get('/', function(req, res, next) {
  res.render('index', { 
  pageTitle: 'Homepage', 
  offerData: Offer.rsProducts(), //calls Offer's rsProducts function to get the data
  storyData: Story.rsStories(), // calls Story's rsStories function to get the data
  qandaData: QandA.rsQandAs(), // calls QandA's rsQandAs function to get the data
  jobData:   Job.rsJobs() // calls Job's rsJobs function to get the data
});
});

标签: node.jsexpress

解决方案


那里需要解释的东西太多了。

如您所见,所有“I/O”函数(例如,连接到数据库、查询到 db ...)都有一个参数function (err, result) {...(如function (error)...),并且作为您的问题“为什么他们不直接返回结果把它包装成一个函数?”。

使用 Javascript,函数就是Callback函数,JS 不像“正常”的程序语言那样工作。

一个针对您的情况的修补程序,我不知道您为什么将rsProduct函数定义req, res, next为参数,但这对我的方式有好处 - 使 rsProduct成为“中间件”函数:

const mssql = require('mssql/msnodesqlv8');

module.exports.rsProduct = function (req, res, next) {

  global.MYDB.connect(function (error) { // MYDB is a mssql-server database setup in app.js as a global variable
    if (error) {
      console.log(error);
      return next(error); // call next with a error to stop flow and throw a error to express app
    }

    global.MYDB.request().query('SELECT Top(1) * FROM [dbo].[Prodcut]', function (err, result) {

      console.log(result); // this works and i see the database recordset in the console

      // !!! Assign the result to a new field of req object
      req.products = result; // maybe what you need is req.products = result.recordset;

      next(); // continue to your function to render view

    });

  })
}

然后在你的路由器中,

var router = require('express').Router();
const mssql = require('mssql/msnodesqlv8');
const Offer = require('../models/product');

// Offer.rsProduct(); // the console.log(result) line in the model file logs the recordset to the console

// console.log(Offer.rsProduct()); // this log does not log anything which means no result is being returned from the model file to this controller

router.get('/', Offer.rsProduct, function (req, res, next) { //  Offer.rsProduct instead of  Offer.rsProduct()
  res.render('index', { pagetitle: 'Product Name', data: req.products }); // get back products list
});

推荐阅读