在Express中多次SELECT查询后呈现视图

时间:2015-01-24 17:41:28

标签: node.js express

我在Node.JS和Express框架中有点新功能,我对下面的代码有一个很大的问题:

app.get('/student', function(req, res) {
    var dbRequest = 'SELECT * FROM Students WHERE IDCard = \'' + req.query['id'] + '\'';
    db.all(dbRequest, function(error, rows) {
        if(rows.length !== 0) {
            /* Save data. */
        }   
        else
            res.render('incorrect_student'); /* Render the error page. */
    });

    dbRequest = 'SELECT * FROM Groups WHERE Name = \'' + req.query['group'] + '\'';
        db.all(dbRequest, function(error, rows) {
            /* Add selected data to previous saved data. */
        }
    });
    res.render('student', {data: /* data from both queries above */});
});

正如我在评论块中所写,我想:执行第一个选择查询,从对象保存数据,执行第二个查询,再次将接收到的数据保存在其他对象中,然后最终渲染页面传递来自两个查询的数据。我的问题是,最好的方法是什么?

我知道匿名函数导致了一个问题。我已经尝试将问题解决了五个多小时,如下所示:

  1. 在匿名函数中将对象克隆到另一个,然后将其传递给 res.render 。这个解决方案不起作用,因为复制对象的值在此函数外部不可见(未定义) - 仅在其中。
  2. 两次呈现学生页面 - 当然真的很天真。
  3. db.all 命令更改为 db.prepare ,然后将 db.run 更改 - 它也不起作用。
  4. 通过匿名函数返回对象,然后将其分配给 app.get var dbRequest 之间定义的外部对象。结果如第1点所述。
  5. 我还想创建"子页面"包含 student 页面的部分,它只需要来自一个查询的变量。另一个想法是使用 db req res app 对象的其他一些功能。但是,正如我之前所说,我是Express的新人,我不知道如何实现我的上述想法。

    请注意,连接表是不可能的 - 事实上,我想制作4-5个查询,然后渲染我的视图。我使用的是SQLite3数据库。

    非常感谢你的帮助!我希望你能帮助我解决我的问题。

2 个答案:

答案 0 :(得分:15)

在您的情况下,我会将数据库调用拆分为单独的调用,并使用next中间件函数。

它看起来像是:

function findStudent(req, res, next) {
    var dbRequest = 'SELECT * FROM Students WHERE IDCard = \'' + req.query['id'] + '\'';
    db.all(dbRequest, function(error, rows) {
        if(rows.length !== 0) {
            req.students = rows;
            return next();
        }

        res.render('incorrect_student'); /* Render the error page. */            
    });
}

function findGroups(req, res, next) {
    dbRequest = 'SELECT * FROM Groups WHERE Name = \'' + req.query['group'] + '\'';
        db.all(dbRequest, function(error, rows) {
            /* Add selected data to previous saved data. */
            req.groups = rows;
            next();
        }
    });
}

function renderStudentsPage(req, res) {
    res.render('student', {
        students: req.students,
        groups: req.groups
    });
}

app.get('/student', findStudent, findGroups,  renderStudentsPage);

当您获得/student时,请先拨打findStudent。 db调用完成后,它将呈现错误页面,或调用next()。接下来调用下一个函数findGroups,然后调用renderStudentsPage。在向下移动函数时,可以将数据存储在req对象上。

希望这会有所帮助,这里有更多信息: http://expressjs.com/guide/using-middleware.html


编辑/注:

我之前没有提到它,但是如果你在调用next()时传入一个参数,你将触发错误处理状态。除非遇到错误实例,否则约定next()保留参数。

您希望将UI呈现方面与数据库调用分开,因此更进一步,您的代码可能如下所示:

function findStudent(req, res, next) {
    var dbRequest = 'SELECT * FROM Students WHERE IDCard = \'' + req.query['id'] + '\'';
    db.all(dbRequest, function(error, rows) {

        if (error || !rows.length) {
            return next(error);
        }

        req.students = rows;
        return next();
    });
}

然后在代码的其他地方,您可以处理渲染错误页面。

答案 1 :(得分:0)

我知道这是一个老问题,但对于任何仍然遇到问题并使用MongoDB的人而言,这对我有用。

//index.js    
const express = require('express');
const router = express.Router();

function getData (req, res, next) {
  var db = req.db;
  var collection = db.get('usercollection');

  collection.find({}, {}, function(e, docs) {
    req.data = docs;
    return next();
  });
}

function getVendor (req, res, next) {
  var db = req.db;
  var collection = db.get('usercollection');

  collection.distinct("vendor", function(e, docs) {
    req.vendor = docs
    next();
  });
}

function getType (req, res, next) {
  var db = req.db;
  var collection = db.get('usercollection');

  collection.distinct("type", function(e, docs) {
    req.type = docs
    next();
  });
}

function renderData(req, res) {
    res.render('index', {
        data: req.data,
        vendor: req.vendor,
        type: req.type
    });
}

/* GET home page. */
router.get('/', getData, getVendor, getType, renderData);


module.exports = router;

然后在你的ejs文件里面

//index.ejs 
<body>
<div id="app">
<h1>Choose a Vendor</h1>
<template v-for="vendor in values.vendor">
  <label :for="vendor">{{ vendor }}</label>
  <input type="radio" :value="vendor" v-model="flagpole.vendor">
</template>

<div>
  <template v-for="type in values.type">
    <label :for="type">{{ type }}</label>
    <input type="radio" :value="type" v-model="flagpole.type">
  </template>
</div>

</div>

<script type="text/javascript">
var vendor = <%- JSON.stringify(vendor) %>
var type = <%- JSON.stringify(type) %>

var vm = new Vue({
  el: '#app',
  data: {
    values: {
      vendor: vendor,
      type: type
    },
    flagpole: {
      vendor: '',
      type: ''
    }
  },