0

Im trying to create a search bar that will query and display the data from my own Postgres database. I have a search bar on my screen, and I think I am connected to my database, but i cannot get any results to show up. Any help would be appreciated. Im still quite new to using node.js and developing tools such as this. When i submit my search, i receive a 404 error message. Index.js

const express = require('express');
const router = express.Router();
const pg = require('pg');
const path = require('path');
const connectionString = process.env.DATABASE_URL || 'postgres://postgres:postgres@localhost:5432/todo';


router.get('/', (req, res, next) => {
  res.sendFile(path.join(
    __dirname, '..', '..', 'client', 'views', 'index.html'));
});

router.get('/api/v1/todos', (req, res, next) => {
  const results = [];
  // Get a Postgres client from the connection pool
  pg.connect(connectionString, (err, client, done) => {
    // Handle connection errors
    if(err) {
      done();
      console.log(err);
      return res.status(500).json({success: false, data: err});
    }
    // SQL Query > Select Data
    const query = client.query('SELECT name FROM world_heritage_sites.caravanserai ORDER BY iso ASC;');
    // Stream results back one row at a time
    query.on('row', (row) => {
      results.push(row);
    });
    // After all data is returned, close connection and return results
    query.on('end', () => {
      done();
      return res.json(results);
    });
  });
});

App.js

const express = require('express');
const path = require('path');
const favicon = require('serve-favicon');
const logger = require('morgan');
const cookieParser = require('cookie-parser');
const bodyParser = require('body-parser');
const routes = require('./server/routes/index');
// var users = require('./routes/users');

const app = express();

// view engine setup
// app.set('views', path.join(__dirname, 'views'));
// app.set('view engine', 'html');

// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'client')));

app.use('/', routes);
// app.use('/users', users);

// catch 404 and forward to error handler
app.use((req, res, next) => {
  var err = new Error('Not Found');
  err.status = 404;
  next(err);
});

// error handlers

// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
  app.use((err, req, res, next) => {
    res.status(err.status || 500);
    res.json({
      message: err.message,
      error: err
    });
  });
}

// production error handler
// no stacktraces leaked to user
app.use((err, req, res, next) => {
  res.status(err.status || 500);
  res.json({
    message: err.message,
    error: {}
  });
});


module.exports = app;

HTML

 <!DOCTYPE html>
<html ng-app="nodeTodo">
  <head>
    <title>Todo App - with Node + Express + Angular + PostgreSQL</title>
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" media="screen">
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
    <script src="/search.js" type="text/javascript"></script>
    <script src="/search.js"></script>
    <script src="//code.jquery.com/jquery-2.2.4.min.js" type="text/javascript"></script>
    <script src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" type="text/javascript"></script>
  </head>
  <body ng-controller="mainController">
    <div class="container">
      <div class="header">
        <h1>SuckySearchBar</h1>
        <hr>
        <h1 class="lead">Designing Search Bars Suck This Never Works</h1>
      </div>
    </body>
    <body ng-controller="searchController">
      <div class="container">
        <div class="search-box">
                <input class="search" type="text" placeholder="Search" id="search" method='GET' autocomplete="on" onkeyup="search();">
                <table class="result table-bordered" id="search"></table>
<script>
                function searchinput(){
                  $.ajax({
                      type: 'GET',
                      url: '/api/v1/todos' + searchinput,
                      success: function(result){
                          window.location.reload(true);
                      }
                  })
                }

                </script>
      </div>
     </body>
</html>

Search.js

function search(search_string, func) {
     pool.query(
        "SELECT name FROM world_heritage_sites.caravanserai ORDER BY iso ASC", 
        [search_string],
        function(err, result) {  
            if(err) {
                func([])
            } else {
                func(result.rows)
            }
        }
    );
}

module.export = search;
2
  • I noticed you are using action and methods attributes on input tag. The action attribute is only supported by form tag not input and method NOT plural methods is also supported by form tag only. Also since you want to call search function you don't need the form at all since that would cause full page reload after submitting. Instead in the search function you should send an ajax request to your server and render the results in the table. Also if /api/v1/todos is the route that returns the results for your search bar why you have /search in the action attribute? Commented Feb 11, 2020 at 17:11
  • Hi Molda, thanks for the quick reply. I updated the HTML portion of my code if you wouldn't mind taking a look at that, i should totally remove the "method" portion as well? Could you break down how I might send an ajax request to my server to render my results to a table? Commented Feb 11, 2020 at 17:37

2 Answers 2

3

first of all, congrats for starting a new studies task! But let's solve this issue, shall we?

1 - My tip for you, is that before you even start to worry about the frontend, let's make sure that our service is running fine, and we shall test it on the server-side only. "I think I am connected to my database", we cannot proceed if we think something is going on fine, we need to make sure!

2 - We need our service running, that`s the only way we can get our DB connected. So for now, we forget about the interface and DB, let's focus on the service: Inside your "app.js" you are trying to import your routes right? By doing

const routes = require('./server/routes/index');

But in order to do that, you need to export those routes before, then go to your "index.js" file and add "module.exports = router". Now you can use your router imported inside your "app.js" file!

Stays like this:

const express = require('express');
const router = express.Router();
const pg = require('pg');
const path = require('path');
const connectionString = process.env.DATABASE_URL || 'postgres://postgres:postgres@localhost:5432/todo';

 Almost there, our service needs to listen to some port now


router.get('/', (req, res, next) => {
  res.sendFile(path.join(
    __dirname, '..', '..', 'client', 'views', 'index.html'));
});

router.get('/api/v1/todos', (req, res, next) => {
  console.log("HAHAHAHAHA")
  const results = [];
  // Get a Postgres client from the connection pool
  pg.connect(connectionString, (err, client, done) => {
    // Handle connection errors
    if(err) {
      done();
      console.log(err);
      return res.status(500).json({success: false, data: err});
    }
    // SQL Query > Select Data
    const query = client.query('SELECT name FROM world_heritage_sites.caravanserai ORDER BY iso ASC;');
    // Stream results back one row at a time
    query.on('row', (row) => {
      results.push(row);
    });
    // After all data is returned, close connection and return results
    query.on('end', () => {
      done();
      return res.json(results);
    });
  });
});

module.exports = router;

Now our application needs to listen to some port. I don't have access to your folder structure, that's why I will work the idea using only these two files you presented us. Inside your "app.js" you got tell your application to serve using one port, you can do that by typing "app.listen(8000, () => console.log('listening')) " since you are exporting your app, you can import and use it anywhere you'd like, but I told you already, I will work the idea restricted to the files you showed us, that's why your "app.js" would be like this check this Docs before : https://node-postgres.com/features/connecting

const express = require('express');
const path = require('path');
const logger = require('morgan');
const cookieParser = require('cookie-parser');
const bodyParser = require('body-parser');
const routes = require('./index');
// var users = require('./routes/users');

const app = express();

// view engine setup
// app.set('views', path.join(__dirname, 'views'));
// app.set('view engine', 'html');

// uncomment after placing your favicon in /public
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'client')));

app.use('/', routes);
// app.use('/users', users);

// catch 404 and forward to error handler
app.use((req, res, next) => {
  var err = new Error('Not Found');
  err.status = 404;
  next(err);
});

// error handlers

// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
  app.use((err, req, res, next) => {
    res.status(err.status || 500);
    res.json({
      message: err.message,
      error: err
    });
  });
}

// production error handler
// no stacktraces leaked to user
app.use((err, req, res, next) => {
  res.status(err.status || 500);
  res.json({
    message: err.message,
    error: {}
  });
});


app.listen(8000, () => console.log('listening'))

module.exports = app;

Ok, now our service is running, go to your terminal and type: node app.js

it should print "listening" in your shell.

Now try to access http://localhost:8000/api/v1/todos in your browser, it should print an error "pg.connect is not a function"

That's because you are not using the lib the right way, try something like this

const express = require('express');
const router = express.Router();
const path = require('path');
const { Pool, Client } = require('pg')
const connectionString = 'postgres://postgres:postgres@localhost:5432/todo'
const client = new Client({
  connectionString: connectionString,
})
client.connect()

router.get('/', (req, res, next) => {
  res.sendFile(path.join(
    __dirname, '..', '..', 'client', 'views', 'index.html'));
});

router.get('/api/v1/todos', (req, res, next) => {
  const results = [];
  client.query('SELECT name FROM world_heritage_sites.caravanserai ORDER BY iso ASC;', (err, res) => {
    console.log(err, res)
    client.end()
  })
});

module.exports = router;

But remember, you need to have your Postgres service running in your localhost to connect using this connection string you are using. If you configured your Postgres service and db the right way, it should work fine, then you just need to call your route "localhost:8000/api/v1/todos" in your interface.

Actually there are a lot of things you should check in your code, and maybe it's good if you get some background before start this project. Try some tutorials for beginners on youtube and check other dev's code. Good Luck and Good code dude! I hope I gave you at least a little help :)

Sign up to request clarification or add additional context in comments.

3 Comments

Hi Nicolas, thank you so much for your response!! I have successfully got my console to list the results of my SQL query, so excited and happy!! you have no idea how long this has stumped me! Really appreciate it. So now if i wanted to look at the front end, i would want to try and connect my router to my search bar?
Hey, glad to know! "localhost:8000/api/v1/todos" it's your endpoint, so you can get the info it retrieves using some HTTP requester, just like ajax and fetch. Since it is a GET method you will need to configure a get method using ajax or fetch or any others you`d like to use. Now you have to create a function that receives your search param and calls "localhost:8000/api/v1/todos" passing this param, changing your Html structure using the results, then you need to put this function inside a trigger in your search bar (onKeyUp, onClick etc). That's one of the ways you can accomplish.
Hi Nicolas, I added some code to my HTML section of code. It represents the AJAX call im trying to do, when i try to search something in my search bar, i am getting a 404 error, any ideas?
0

I think what @Molda is saying is that you should change methods=['GET'] to method='GET'. Can you post the surrounding html as well?

EDIT

Ok, so I think you are confusing the javascript running on your server and the javascript running in the browser. If you are going to call search() from the onKeyUp() event handler Then it is going to run in the browser. Since it is going to run in the browser, it does not have the ability to access postgres directly. What it should do is make an ajax request to a route on the server that provides it with the search results as json (similar to what you did with /api/v1/todos you could define /api/v1/search), which it then renders on the page somehow (perhaps with jquery). In this case, you shouldn't even need to define method on your input.

4 Comments

Hi C-RAD, I edited my question to include all of the HTML that I am using. Again thank you for your help, this problem has plagued me for a long time.
np. Can you also add your search() function?
Actually the entirety of search.js will probably prove useful.
I have edited my question to include the search.js portion, its below the HTML

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.