Визуализация представления после нескольких запросов 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 */});
});

Как я писал в комментариях, я хотел бы: выполнить первый запрос на выборку, сохранить данные из объекта строк, выполнить второй запрос, снова сохранить полученные данные в другом объекте и, наконец, отобразить страницу, передающую данные из обоих запросов. Мой вопрос, каков наилучший способ сделать это?

Я знаю, что есть проблема, вызванная анонимной функцией. Более пяти часов я пытался решить проблему следующим образом:

  1. Клонировать строки объекта в анонимную функцию, а затем передать его в res.render. Это решение не работает, потому что значения скопированного объекта не видны (не определены) вне этой функции - только внутри нее.
  2. Визуализируйте страницу ученика дважды - конечно, это было действительно наивно.
  3. Измените команду db.all на db.prepare, а затем db.run - она ​​тоже не работала.
  4. Вернуть объект анонимной функцией, а затем назначить его внешнему объекту, определенному между 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: ''
    }
  },
Другие вопросы по тегам