Визуализация представления после нескольких запросов SELECT в Express
Я немного новичок в Node.JS и Express Framework, и у меня есть большая проблема с кодом ниже:
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 */});
});
Как я писал в комментариях, я хотел бы: выполнить первый запрос на выборку, сохранить данные из объекта строк, выполнить второй запрос, снова сохранить полученные данные в другом объекте и, наконец, отобразить страницу, передающую данные из обоих запросов. Мой вопрос, каков наилучший способ сделать это?
Я знаю, что есть проблема, вызванная анонимной функцией. Более пяти часов я пытался решить проблему следующим образом:
- Клонировать строки объекта в анонимную функцию, а затем передать его в res.render. Это решение не работает, потому что значения скопированного объекта не видны (не определены) вне этой функции - только внутри нее.
- Визуализируйте страницу ученика дважды - конечно, это было действительно наивно.
- Измените команду db.all на db.prepare, а затем db.run - она тоже не работала.
- Вернуть объект анонимной функцией, а затем назначить его внешнему объекту, определенному между app.get и var dbRequest. Результат был таким, как описано в 1-м пункте.
У меня также есть идея создать "подстраницы", содержащие в себе части страницы ученика, которым нужны переменные только из одного запроса. Другая идея заключается в использовании некоторых других функций объектов db, req, res или app. Но, как я уже говорил, я новичок в Express, и я не знаю, как реализовать мои идеи выше.
Обратите внимание, что невозможно объединить таблицы - на самом деле я хочу сделать 4-5 запросов, а затем отобразить свое представление. Я использую базу данных SQLite3.
Большое спасибо за Вашу помощь! Я надеюсь, что вы поможете мне решить мою проблему.
2 ответа
В вашей ситуации я бы разделил вызовы базы данных на отдельные вызовы и использовал бы 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(). Вызов next переходит к следующей функции, findGroups
, который потом позвонит renderStudentsPage
, Вы можете сохранить данные в объекте req при перемещении вниз по строке функций.
Надеюсь, это поможет, и вот больше информации: http://expressjs.com/guide/using-middleware.html
редактировать / примечание:
Я не упоминал об этом раньше, но если вы передаете аргумент при вызове next()
, вы будете вызывать состояние обработки ошибок. Конвенция диктует next()
остается без параметров, если вы не встретили экземпляр ошибки.
Вы хотите отделить аспект визуализации пользовательского интерфейса от вызова базы данных, поэтому в дальнейшем ваш код может выглядеть следующим образом:
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();
});
}
И затем в другом месте вашего кода вы можете обрабатывать страницы ошибок рендеринга.
Я знаю, что это старый вопрос, но для тех, кто все еще испытывает проблемы и использует 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: ''
}
},