Search code examples
javascriptnode.jspostgresqlexpresspg-promise

How to separate controller and database queries for Node and pg-promise


I am writing a web application to display a web page with content from a PostgreSQL database using NodeJS, express and pg-promise.

I have a database javascript called "db/location.js" which query the location table.

var db_global = require('./db');  # db.js is for building the database connection
var db = db_global.db;

var locationList = [];

// add query functions

module.exports = {      
  getAllLocationList: getAllLocationList,
  locationList: locationList
};

function getAllLocationList() {
  db.any('select * from location')
    .then(function (data) {
        console.log(data);
        locationList = data;
    }
  );
}

In the routes folder, I have a route javascript called "locationRoute.js".

var express = require('express');
var router = express.Router();

var db = require('../db/location');

/* GET home page. */
router.get('/', function(req, res, next) {
  res.render('index', { title: 'Express' });
});

/* GET the map page */
router.get('/locations', function(req, res) {
  db.getAllLocationList();
  console.log(db.locationList);

  res.render('locations', {
    title: "Express and Leaflet API", // Give a title to our page
    //jsonData: db.getAllLocations // Pass data to the View
    jsonData: db.locationList // Pass data to the View
  });
});

module.exports = router;

When "http://localhost:3000/locations" is called, this is supposed to render the "locations.jade" which is to display "db.locationList" in a table.

My issue is that "console.log(db.locationList);" is always called before the query was completed. This caused "db.locationList" (jsonData) to be empty.

I don't want to mess the controller layer with the database layer but how to fix the issue?


Solution

  • I think you should change your db/location.js to be something like this...

    function getAllLocationList() {
      return db.any('select * from location');
    }
    

    Then you would do something like this in your routes...

    router.get('/locations', function(req, res) {
      db.getAllLocationList()
       .then(function(data) {
          res.render('locations', {
              title: "Express and Leaflet API", // Give a title to our page
              jsonData: data // Pass data to the View
          });
      });
      ...
    

    In your example console.log(db.locationList); runs before the data is available, because it's asynchronous. It doesn't work the way you're expecting it to work.