Reading a JSON file in NodeJs - json

I have a small JSON file with this content
{
"users": [
{
"id": 1593,
"name": "Foo Bar"
}
]
}
and I want to read this content by using the filesystem module. So my application looks this
const fs = require('fs');
const express = require('express');
const app = express();
app.get('/users/:id', function (req, res) {
fs.readFile('./userDb.json', 'utf8', function (err, data) {
var json = JSON.parse(data);
var users = json.users;
console.log(users[0].id); // returns 1593
console.log(req.params.id); // returns 1593
var userObj = null;
for(var i = 0; i < users.length; i++){
var currentUser = users[i];
console.log(currentUser.id); // returns 1593
if (currentUser.id === req.params.id) { // this should be fine 1593 === 1593
userObj = currentUser;
break;
}
}
console.log(userObj); // returns undefined
res.render('users', {
user: userObj
});
});
});
app.listen(3000, function () {
console.log('Server running on port 3000');
});
The log will always return 1593, when I pass it as a parameter but when I want to render my handlebars template, the assigned object is null.
userObj is null, even when trying this code
var userObj = users.find(u => u.id === req.params.id);
but I think the database is not wrong. Where did I made a mistake =?

Pretty sure that req.params.id is a String. Try :
const userObj = users.find(u => u.id === Number(req.params.id));
When you have a doubt about it :
console.log(
`First value : ${v1} - ${typeof v1}`,
`Second value : ${v2} - ${typeof v2}`,
);

Please replace
if (currentUser.id === req.params.id)
with
if (currentUser.id == req.params.id)
Since req.params.id is a string and and currentUser.id is a number, they cannot be compared strictly .
However a non-strict comparison should work fine.

console.log(userObj); // returns undefined
is called after the readFile callback, this is an asynchronous non-blocking event!
You have to move your:
res.render('users', {
user: userObj
});
at the end of readFile function

Related

Why am i getting undefined when trying to get a single element?

Why am i getting undefined of my id? I am creating an app with NextJS and i am trying to do a route to get an especific element by its id. This is my route:
const { events } = require('../../../db.json')
const handler = async (req , res) => {
const method = req.method;
const evt = events.filter((ev) => ev.id === req.query.params.id);
if(method === 'GET'){
return res.status(201).json(evt);
} else {
res.setHeader('Allow', ['GET']);
res.status(405).json({message:`Method ${method} is not allowed`})
}
}
For some reason i get this error when i go to http://localhost:3000/api/events/1
I am using json web server so i have my api also running in port 3001 so at http://localhost:3001/api/events/1 it works and show the corresponding id but why is not working in port 3000 also?
Try updating your code to the following:
const { events } = require('../../../db.json');
const handler = async (req, res) => {
const method = req.method;
const id = req.query.id;
const evt = events.filter((ev) => ev.id === id);
if (method === 'GET') {
return res.status(201).json(evt);
} else {
res.setHeader('Allow', ['GET']);
res.status(405).json({ message: `Method ${method} is not allowed` });
}
};

Node loop insert with mySQL and Mongodb

I have a form with one field that allows user to enter multiple developer id via comma delimited (ab1234,bc5678).
Once the form is submitted I perform the following tasks:
Get the the project
Loop through array of developer IDs to get their full name using mySQL
update the project using MongoDB
I'm new and sure this this is possible, The codes I have below is not working for me. Can someone please let me know if the codes below is even close.
const mongoose = require('mongoose'
const mysql = require('mysql');
// Create mySQL connection
const mySQLdb = mysql.createConnection({
host : 'localhost',
user : 'root',
password : 'root',
database : 'projects'
});
const Project = mongoose.model('project');
router.post('/developerSave', async (req, res) => {
let devList = req.body.dev_ids,
devIdArr = devList.split(','),
rData = {};
// get project
const project = await Project.findById(req.body.projectID);
mySQLdb.connect();
for(var i=0, len=devIdArr.length; i < len; i++) {
let sql = `SELECT CONCAT(first_name, ' ', last_name) as full_name FROM users WHERE id= '${devIdArr[i]}'`;
mySQLdb.query(sql, function (err, results) {
if (err) throw err;
let newDev = {
userId: devIdArr[i],
fullName: results[0].full_name
}
project.developers.unshift(newDev);
await project.save();
});
}
mySQLdb.end();
rData.success = true;
rData.msg = 'Developer was added successfully.';
res.status(200).json(rData);
});
The reason you are seeing this is because your await project.save(); is inside the callback function. Your main function will not wait for all the callbacks to complete and close the db connection. Lets look at the example below
const myCallback = (param, callback) => {
setTimeout(() => {
console.log('callback function', param);
callback();
}, 1000)
}
const myAsync = async () => {
console.log('inside async');
const result = await axios.get('http://google.com/');
for (let i = 0; i < 10; i++) {
myCallback(i, () => {
console.log('this is the actual callback function');
});
}
const result2 = await axios.get('http://bing.com/');
console.log('after second call');
}
myAsync();
The output of this is
inside async
after second call
callback function 0
this is the actual callback function
...
As you can see, the after second call is printed before the callback functions.
To solve this problem, you can wrap your callback function in a promise and resolve that once save is complete.

Object is null when reading from JSON in NodeJs

I got this server code running
const fs = require('fs');
const express = require('express');
const app = express();
app.get('/profile/:id', function (req, res) { // A route with a parameter
res.render('profile', {
user: getUserById(req.params.id)
});
});
app.listen(8888, function () {
console.log('Server running on port 8888');
});
function getUserById(userId){
fs.readFile('./database.json', 'utf8', function (err, data) {
var json = JSON.parse(data);
var users = json.users;
return users.find(u => u.id === userId);
});
}
And when calling the route, the function getUserById gets called. In my database, I have this data
{
"users": [
{
"id": 2312,
"name": "Foo Bar",
}
]
}
so the route would be /profile/2312 for example.
req.params.id returns the value 2312.
In the loop at var currentUser = users[0]; currentUser.id will return 2312 and the parameter passed in is 2312.
But when assigning user = currentUser; the object user is null.
Do I miss a module? Is the code wrong?
user object is null because you are returning it before your code actually reads the file.
fs.readFile('./database.json', 'utf8', function (err, data) { }
fs.readFile is asynchronous, so in order to return correct value you have to move the return statement inside fs.readFile block.
Also since getUserById is calling an asynchronous function, you have to call res.render after 'getuserById' finishes executing.
const fs = require('fs');
const express = require('express');
const app = express();
app.get('/profile/:id', getUserById);
app.listen(8888, function () {
console.log('Server running on port 8888');
});
function getUserById(req,res){ // Get a user from the database by userId
const userId = req.params.id;
fs.readFile('./database.json', 'utf8', function (err, data) {
var json = JSON.parse(data); // get the JSON object
var users = json.users; // convert the object to a user array
var match = users.find(u=>u.id.toString()===userId.toString());
//Call render after the asynchronous code finishes execution.
res.render('profile', {
user: match
});
});
}
How does Asynchronous Javascript Execution happen? and when not to use return statement?

Node.js sequential mysql queries promise not resolving

A route in app.js calls a function register(user) in a MySQL model, model.js. This register() calls displayNameTaken(display_name) which will return null if display name is available otherwise it will return a json object.
The promise in the app.post containing model.register(req.body) does not resolve.
If display name is taken register() will pass this json object back to the calling route.
If display name is not taken register() will register user and return back another json object back to the calling route.
The app never resolves the returned promise, app#113.
Or do you have any suggestions to what I should do instead?
Can you see what I have done wrong?
Output below:
1. When display name taken
app#113 [ undefined ]
model#73 { code: 12, message: 'e' }
2. Display name not taken, registration successful
app#113 [ undefined ]
model#73 undefined
model#61 110 //<- last insert id
The app never resolves the returned promise, app#113.
Or do you have any suggestions to what I should do instead?
Can you see what I have done wrong?
app.post('/api/register', function (req, res) {
Promise.all([
model.register(req.body)
]).then((r => {
console.log('app#113',r);// r=> undefined
res.status(200).json(r);
})).catch((e => {console.log(e);
res.status(500).json(e);
}));
});
function Model(db){
this.db = db;
}
//Function returns null if display name is not taken
Model.prototype.displayNameTaken = function(display_name){
return new Promise((resolve, reject, next) => {
var sql = "SELECT id FROM `users` WHERE `display_name` = ?";
var rv;
this.db.query(sql, [[display_name]], (err, result) => {
if (err) {
return resolve(err);
}
if(0 < result.length && result[0].id != undefined && result[0].id != NaN && 0 < result[0].id){
rv = {code: 12, message:'e'};
}else{
rv = null;
}
return resolve(rv);
});
});//Promise
}
model.register = function register(params){
if(params == undefined){
return;
}
var rv;
Promise.all([
this.displayNameTaken(params.display_name.trim())
]).then((r => {
return new Promise((resolve, reject, next) => {
if(r[0] == null){//display_name available
var sql = "INSERT INTO `users` (`display_name`, `email`, `hash`, `created`,`md51`, `md52`, `language`) VALUES ?";
var md51 = md5(randomString({length:32}));
var md52 = md5(randomString({length:32}));
var user = [[
params.display_name.trim(),
params.email.trim(),
passwordHash.generate(params.hash.trim()),
datetime.create().format('Y-m-d H:M:S'),
md51,
md52,
params.language
]];
this.db.query(sql, [user], function (err, result) {
if (err) {
return reject(err);
}
console.log('model#61',result.insertId);
if(0 < result.insertId){
rv = {code: 8, message:'i', md51: md51, md52: md52};
}else{
rv = {code: 0, message:'e'};
}
return resolve(rv);
});
}else{//display_name taken
rv = r[0];
}
console.log('model#73',rv);
return resolve(rv);
});//Promise
})).catch((e => {
console.log(e);
}));

Node.js : Write new data to an existing json file

I'm trying to add data to an existing json file (codes below). When I access the locahost, the new piece of data shows up, however, when I check the data (users.json), the new piece of data (i.e. user4) isn't there.
Does anyone know what's wrong with the code? Thank you!
var express = require('express');
var app = express();
var fs = require("fs");
var user = {
"user4" : {
"name" : "mohit",
"password" : "password4",
"profession" : "teacher",
"id": 4
}
}
app.get('/addUser', function (req, res) {
// First read existing users.
fs.readFile( __dirname + "/" + "users.json", 'utf8', function (err, data) {
data = JSON.parse( data );
data["user4"] = user["user4"];
console.log( data );
res.end( JSON.stringify(data));
});
})
var server = app.listen(8081, function () {
var host = server.address().address
var port = server.address().port
console.log("Example app listening at http://%s:%s", host, port)
})
EDIT:
I added fs.writeFile(...) (codes below). After running the code, the only content of the uers.json file is:utf8
var express = require('express');
var app = express();
var fs = require("fs");
var user = {
"user4" : {
"name" : "mohit",
"password" : "password4",
"profession" : "teacher",
"id": 4
}
}
app.get('/addUser', function (req, res) {
// First read existing users.
fs.readFile( __dirname + "/" + "users.json", 'utf8', function (err, data) {
data = JSON.parse( data );
data["user4"] = user["user4"];
console.log( data );
// res.end( JSON.stringify(data));
data = JSON.stringify(data);
fs.writeFile(__dirname+"/"+"users.json", "utf8", function(err,data){
if (err){
console.log(err);
};
res.end(data);
});
});
})
To write to a file you should use fs.writeFile.
fs.writeFile(__dirname + "/" + "users.json", user["user4"], 'utf8', function()
{
// do anything here you want to do after writing the data to the file
});
I have passed data to writeFile so that it may write the information in data variable to JSON
fs.readFile( __dirname + "/" + "users.json", 'utf8', function (err, data) {
data = JSON.parse( data );
data["user4"] = user["user4"];
console.log( data );
data = JSON.stringify(data);
fs.writeFile(__dirname + "/" + "users.json", data , 'utf8', function(err,data) {
if (err){
console.log(err);
};
res.end(data);
});
});