Pull mongo data to ejs template - node.js

I have the following basic document in mongo:
connecting to: test
> db.car.find();
{ "_id" : ObjectId("5657c6acf4175001ccfd0ea8"), "make" : "VW" }
I am using express, mongodb native client (not mongoose) and ejs.
collection.find().toArray(function (err, result) {
if (err) {
console.log(err);
} else if (result.length) {
console.log('Found:', result);
mk = result;
console.log('mk = ', mk);
} else {
console.log('No document(s) found with defined "find" criteria!');
}
//Close connection
db.close();
});
}
});
Here is the render code:
// index page
app.get('/', function(req, res) {
res.render('pages/index', { make: result });
});
And i want to pass the data make: VW into my index.ejs file:
<h2>Cars:</h2>
<h3>My favorite make is <%= make %>
This should be real simple and straightforward but i just don't understand how to pass the "mk" variable (which i can console.log to the screen) to be rendered by the ejs view?

You should use the find method inside the route (or with a callback) to get the result and render it:
app.get('/', function(req, res) {
collection.find().toArray(function(err, result) {
if(err) {
console.log(err);
res.status('400').send({error: err});
} else if(result.length) {
console.log('Found:', result);
mk = result;
console.log('mk = ', mk);
res.render('pages/index', {make: mk});
} else {
console.log('No document(s) found with defined "find" criteria!');
res.status('400').send({error: 'No document(s) found'});
}
//Close connection
db.close();
});
});

Very simple, your are outputting an array of JSON objects
Here is one way to visualise it:
[{a:b},{a:b},{a:b},{a:b}];
If you want the first result it would be array[0].a
so you simply need to call it this way:
<%= make[0].(your database key here) =>
//example
<%= make[0].name =>
A more sensible way to get this done would be to iterate through the array and output only the result you want on the server side. If you send all your data to your client you might have security issues depending on what you send.

It should be simple, but you are defining mk just like this: mk = result So because you want to pass a variable to an ejs file you need
"var mk = result"
Have a good day, Ben.

Related

Cannot create property '_locals' on string

Hello im trying to select from my databas however it [Object,object]. Then I searched around and got the answer to stringify, however now I got a new issues saying "Cannot create property '_locals' on string " anybody knows how to solve it?
app.get('/behandlare', function(req, res){
pool.connect(function(err, table, done){
if(err) {
return console.error('error fetching staff from table', err);
}
table.query('SELECT * FROM public.staff', function(err, result){
if(err){
return console.error('error runnig query', err);
}
res.render('behandlare.ejs', JSON.stringify({staff: result.rows}));
done();
});
});
});
.ejs
<div class = "ruta">
<img src="img/spakvinna.jpg" alt="" style="width:400px;height:250px;"><%= name %>
<p class="sida2"></p>
</div>
OK, so i'm assuming that res.render('behandlare.ejs', JSON.stringify({staff: result.rows})); actually requires an object in express and not a string... so instead of doing stringify just pass the object. Ummm... I assume that you might be using it in a wrong way in the template you are using or something of that sort but if it gets you back to the previous error maybe that was the real problem and you need to see how to solve that.
Inside res.render has to be an object literal
// option 1
const myObj = {
obj: req.body,
hats:["white","grey","black"]
};
res.render( 'success', { myObj } )
// or option 2
res.render( 'success', { myObj: req.body } )
It have to be literally an object
Object Definition
How-to define (and create) a JavaScript object with an object literal
const myObj = {
firstName:"John",
lastName:"Doe",
age:50,
eyeColor:"blue"
};

GET request with different mongo find results on same page

I would like my website to have a search bar in the top section that returns a single document (ink) from a mongo database. On the same page, I would like to be able to access all documents from the same database.
I'm having trouble trying to figure out how to do this on one page, since I can only send one result to URL.
Is there some way to send all documents to the page, then do a search with AJAX on the client side? I'm new to coding, and wondering if I'm going about this wrong.
I appreciate any help. Here is part of my code that sends the results I want, but to different pages.
app.get("/", function(req, res){
// FIND ONE INK FROM DB
var noMatch = null;
if(req.query.search) {
Ink.find({ink: req.query.search}, function(err, foundInk){
if(err){
console.log(err);
} else {
if(foundInk.length < 1) {
noMatch = "No match, please try again.";
}
res.render('new-index', {ink: foundInk, locationArray: locationArray, noMatch: noMatch })
}
});
} else {
// FIND ALL INKS FROM DB
Ink.find({}, function(err, allInks){
if(err){
console.log(err);
} else {
res.render("index", {ink: allInks, locationArray: locationArray, noMatch: noMatch });
}
});
}
});
You can use separated endpoints for each request. For the full access request, you can render the page, calling res.render, and for the search request, you can return a json calling res.json. Something like this:
app.get("/", function(req, res){
// FIND ALL INKS FROM DB
Ink.find({}, function(err, allInks){
if(err){
console.log(err);
} else {
res.render("index", {ink: allInks, locationArray: locationArray, noMatch: noMatch })
}
});
})
app.get("/search", function(req, res) {
// FIND ONE INK FROM DB
var noMatch = null;
Ink.findOne({ink: req.query.search}, function(err, foundInk){
if(err){
console.log(err);
} else
if(!foundInk) {
noMatch = "No match, please try again.";
}
res.json({ink: foundInk, locationArray: locationArray, noMatch: noMatch })
}
});
});
Note the call to Ink.findOne in the /search handler, which will return only one document.
This way you can make and AJAX request to /search, and parse the json returned from the server.
I've created a sample repository with the exact same issue here
Ideally you make an endpoint like this.
( id parameter is optional here...thats why the '?' )
www.example.com/api/inks/:id?
// return all the inks
www.example.com/api/inks
// return a specific ink with id=2
www.example.com/api/inks/2
So now you can render all the links via /inks and search a particular ink by using the endpoint /ink/:id?
Hope this helps !

How To Bind Node-js DB Query to Web Form

I'm using node and postgres, I'm new to writing async function, what I'm trying to do is a very simple query that will do a total count of records in the database, add one to it and return the result. The result will be visible before the DOM is generated. I don't know how to do this, since async function doesn't return value to callers (also probably I still have the synchronous mindset). Here's the function:
function generateRTA(callback){
var current_year = new Date().getFullYear();
const qry = `SELECT COUNT(date_part('year', updated_on))
FROM recruitment_process
WHERE date_part('year', updated_on) = $1;`
const value = [current_year]
pool.query(qry, value, (err, res) => {
if (err) {
console.log(err.stack)
} else {
var count = parseInt(res.rows[0].count) + 1
var rta_no = String(current_year) + '-' + count
callback(null, rta_no)
}
})
}
For the front-end I'm using pug with simple HTML form.
const rta_no = generateRTA(function (err, res){
if(err){
console.log(err)
}
else{
console.log(res)
}
})
app.get('/new_application', function(req, res){
res.render('new_application', {rta_number: rta_no})
});
I can see the rta_no in console.log but how do I pass it back to the DOM when the value is ready?
Based on the ajax call async response, it will update the div id "div1" when it gets the response from the Node js .
app.js
app.get("/webform", (req, res) => {
res.render("webform", {
title: "Render Web Form"
});
});
app.get("/new_application", (req, res) => {
// Connect to database.
var connection = getMySQLConnection();
connection.connect();
// Do the query to get data.
connection.query('SELECT count(1) as cnt FROM test ', function(err, rows, fields) {
var person;
if (err) {
res.status(500).json({"status_code": 500,"status_message": "internal server error"});
} else {
// Check if the result is found or not
if(rows.length==1) {
res.status(200).json({"count": rows[0].cnt});
} else {
// render not found page
res.status(404).json({"status_code":404, "status_message": "Not found"});
}
}
});
// Close connection
connection.end();
});
webform.pug - Via asynchronous call
html
head
script(src='https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js')
script.
$(document).ready(function(){
$.ajax({url: "/new_application", success: function(result){
$("#div1").html(result.count);
}});
});
body
div
Total count goes here :
#div1
value loading ...
That seems okay, I'm just not sure of this:
The result will be visible before the DOM is generated
This constraint defeats the purpose of async, as your DOM should wait for the returned value to be there. Instead of waiting for it you could just render the page and once the function returns and runs your callback update the value.
Also, perhaps it's worth having a look into promises

Return 404 code in proper way instead empty array

I have an quite simple application the idea is that someone has unique code which value are stored in one mongo collection in other we are keeping some data which we need to return if the key was found in first collection.
As probably you have noticed I'm using NodeJS with MongoDB and Mongoose, Express.
I have a problem with method bellow:
exports.getCompanyByKey = function(req, res) {
console.log(req.params.keyvalue);
var query = Company.where({keyValue : req.params.keyvalue});
query.findOne(function(err, company){
if(err){
res.send(err);
}else{
SampleData.findOne({}, function(err, sample_data){
if(err)
res.send(err);
res.json(sample_data);
});
}
});
};
The problem is that it will always return the data beause it's not throwing an error but empty array - so is there any other good and proper way as it should be don to throw 404 error without statement such as if(length<0) res.status(404).send('Error message).
I simply want to minimalize amount of if statements.
Maybe there is some other way to write implementation od error handling for mongoose which in general instead returning empty array will give us error code with message?
It's not exactly clear what you're asking, but if you want to make an error condition out of something that is not normally an error, then an if statement (or some other test like that) is required to test for that specific condition.
You could make your own function for querying that turns an empty response into an error and you could "hide" the if condition in that function if you want, but it's still an if condition that tests for your specific condition.
So, to return a 404 if the array is empty, you would just add an if statement (as you already appear to know):
exports.getCompanyByKey = function(req, res) {
console.log(req.params.keyvalue);
var query = Company.where({keyValue : req.params.keyvalue});
query.findOne(function(err, company){
if(err){
res.status(500).send(err);
} else {
SampleData.findOne({}, function(err, sample_data){
if(err) {
res.status(500).send(err);
} else {
if (sample_data.length) {
res.json(sample_data);
} else {
res.status(404).send("no data");
}
}
});
}
});
};
FYI, you also need to make sure you are properly setting a status code when there's an error and that you are never sending multiple responses to the same request (even when there's an error). I've also fixed several cases of those issues in your code.
This could likely be written cleaner and responses consolidated by using the promise interface to your database and send an error in one .catch().
For example, you could simplify your code by creating a utility function for .findOne() that detects and sends an error response automatically:
function findOne(res, db, q, cb) {
db.findOne(q, function(err, data) {
if (err) {
res.status(500).send(err);
cb(err);
} else if (!q.length) {
res.status(404).send("no data");
cb(new Error("no data"));
} else {
cb(null, data);
}
});
}
Then, your function could be simplified to this:
exports.getCompanyByKey = function(req, res) {
var query = Company.where({keyValue : req.params.keyvalue});
query.findOne(function(err, company){
if(err){
res.status(500).send(err);
} else {
findOne(res, SampleData, {}, function(err, sample_data) {
// any error response has already been sent
if (!err) {
res.json(sample_data);
}
});
}
});
};
Again, this would be better to use your Db's promise interface.

Trying to implement callback, or some way to wait until my get request is done. This is in node.js express

Im trying to implement some way to stop my code to redirect me before I get the response from the omdb api I am using.
My function for making a search for a movie and saving all titles in a session looks like this:
app.post('/search', isLoggedIn, function(req, res) {
function getMovies(arg, callback){
console.log('In getMovies');
console.log('searching for '+arg);
omdb.search(arg, function(err, movies) {
if(err) {
return console.error(err);
}
if(movies.length < 1) {
return console.log('No movies were found!');
}
var titles = [];
movies.forEach(function(movie) {
// If title exists in array, dont push.
if(titles.indexOf(movie.title) > -1){
console.log('skipped duplicate title of '+movie.title);
}
else{
titles.push(movie.title);
console.log('pushed '+movie.title);
}
});
// Saves the titles in a session
req.session.titles = titles;
console.log(req.session.titles);
});
// Done with the API request
callback();
}
var title = req.body.title;
getMovies(title, function() {
console.log('Done with API request, redirecting to GET SEARCH');
res.redirect('/search');
});
});
However I dont know if I implement callback in the right way, because I think there can be a problem with the api request actually executing before the callback, but not finishing before. And therefor the callback is working..
So I just want 2 things from this question. Does my callback work? And what can I do if a callback won't solve this problem?
Thankful for all answers in the right direction.
Add
callback();
To, like this
omdb.search(arg, function(err, movies) {
if (err) {
return console.error(err);
}
if (movies.length < 1) {
return console.log('No movies were found!');
}
var titles = [];
movies.forEach(function(movie) {
// If title exists in array, dont push.
if (titles.indexOf(movie.title) > -1) {
console.log('skipped duplicate title of ' + movie.title);
} else {
titles.push(movie.title);
console.log('pushed ' + movie.title);
}
});
// Saves the titles in a session
req.session.titles = titles;
callback();
});
omdb.search is asynchronous function that's why callback executed before omdb.search

Resources