Having issues with socket.io and Async queries - node.js

I am trying to pass information from a database lookup through socket.io and I am having more troubles than I thought I would.
Here is the socket.io emit:
module.exports = (app, io) => {
io.sockets.on('connect', async socket => {
if (!socket.handshake.session.passport) {
return socket.emit('redirect');
}
//Online
console.log(Object.keys(app.online).length);
//Load up
await loadup(app, socket).then(data => {
console.log(data);
});
await socket.emit('load up', loadup(app, socket));
}
(I tried multiple ways to get the desired data to show)
Here is the actual method:
const statHandler = require('./loadhandling/statload');
const User = require('../models/User');
module.exports = async (app, socket) => {
let isOnline = app.online[socket.handshake.session.passport.user];
if (!isOnline) return;
// Start the loadup process
User.findById(socket.handshake.session.passport.user, (err, user) => {
if (err) console.log(err);
let userdata = user.meta;
statHandler(userdata);
return userdata;
});
};
I've always seemed to struggle in these situations for some reason.

I managed to fumble my through this:
Socket.io
module.exports = (app, io) => {
io.sockets.on('connect', async socket => {
if (!socket.handshake.session.passport) {
return socket.emit('redirect');
}
//Online
console.log(Object.keys(app.online).length);
//Load up
const load = await loadup(app, socket);
await socket.emit('load up', load);
}
Method:
const statHandler = require('./loadhandling/statload');
const User = require('../models/User');
module.exports = async (app, socket) => {
let isOnline = app.online[socket.handshake.session.passport.user];
if (!isOnline) return;
// Start the loadup process
const thisUser = await User.findById(
socket.handshake.session.passport.user,
(err, user) => {
if (err) console.log(err);
}
).then(user => {
let userdata = user.meta;
statHandler(userdata);
return new Promise((res, rej) => {
res({ userdata });
});
});
return await thisUser;
};
I'm sure theres a more efficient way, but I don't feel like finding one. Hope this helps someone in the future.

Related

Async await in typescript not working as expected

I wrote a method in typescript which is supposed to return collection list name of mongo db.
public async getTables(): Promise<String[]> {
let collectionNames = [];
const connection = await mongoose.connect("mongodb://localhost/test");
await mongoose.connection.on('open', async function () {
mongoose.connection.db.listCollections().toArray(function (err, tables) {
console.log(tables);
tables.forEach(element => {
collectionNames.push(element["name"]);
});
console.log(collectionNames);
mongoose.connection.close();
});
});
return collectionNames;
}
Problem is instead of awaiting it returns directly empty collection list name.What is the issue here.
Because you use "await" in here,
const connection = await mongoose.connect("mongodb://localhost/test");
So, you miss "open" event that mongoose connection emit.
You can remove "await" for your program run as you expected
public async getTables(): Promise<String[]> {
let collectionNames = [];
const connection = mongoose.connect("mongodb://localhost/test");
await mongoose.connection.on('open', async function () {
mongoose.connection.db.listCollections().toArray(function (err, tables) {
console.log(tables);
tables.forEach(element => {
collectionNames.push(element["name"]);
});
console.log(collectionNames);
mongoose.connection.close();
});
});
return collectionNames;
}
Or you can write as below
public getTables(): Promise<String[]> {
return new Promise(async (resolve, reject) => {
try {
let collectionNames = [];
const connection = await mongoose.connect("mongodb://localhost/test");
mongoose.connection.db.listCollections().toArray(function (err, tables) {
console.log(tables);
tables.forEach(element => {
collectionNames.push(element["name"]);
});
console.log(collectionNames);
mongoose.connection.close();
resolve(collectionNames);
});
} catch (e) {
reject(e);
}
})
}

Can't insert JSON file into MongoDB's collection throught Node driver

I'm trying to read files from my disk and push it into MongoDB's collections, but connection closing before it done and I get error: MongoError: Topology is closed, please connect.
async function launch() {
try {
await mongo.connect();
console.log("Connection established");
const database = mongo.db('task');
const firstCol = database.collection('first');
const secondCol = database.collection('second');
const insertIntoCollection = async (file, col) => {
fs.readFile(file, async function(err, data) {
if (err) throw err;
const json = JSON.parse(data);
const result = await col.insertMany(json);
console.log(result.insertCount);
});
}
await insertIntoCollection('data/first.json', firstCol);
await insertIntoCollection('data/second.json', secondCol);
} finally {
await mongo.close();
}
}
launch().catch(console.dir);
What am I doing wrong?
In the above case mongo client will close before the insertIntoCollection function trigger since it is a promise function and promise will not over before the finally trigger.I hope below code will fulfil your expectations.
async function launch() {
try {
await mongo.connect();
console.log("Connection established");
const database = mongo.db('task');
const firstCol = database.collection('first');
const secondCol = database.collection('second');
const insertIntoCollection = async (file, col) => {
return new Promise((resolve, reject) => {
fs.readFile(file, async (err, data) => {
try {
if (err) reject(err);
const json = JSON.parse(data);
const result = await col.insertMany(json);
console.log(result.insertCount);
resolve(result.insertCount)
} catch (err) {
reject(err)
}
});
})
}
await insertIntoCollection('data/first.json', firstCol);
await insertIntoCollection('data/second.json', secondCol);
} finally {
await mongo.close();
}
}
launch().catch(console.dir);

How can I get list record from SQL Server in NodeJS

I start to develop a simple web application with NodeJS. and when I try to get a list record from SQL Server to show on the list page but somehow it's not working.
Here is the code :
const express = require("express");
const bodyParser = require("body-parser");
const sql = require("mssql");
const DBUtils = require("./DBUtils");
const app = express();
app.get("/all", (req, res, next) => {
let mypromise = new Promise((reso, rej) => {
let nameList = DBUtils.getNameList(sql);
if (nameList !== null || typeof nameList !== "undefined") {
reso(nameList);
} else {
rej("Error");
}
})
.then((result) => {
res.send(result);
})
.catch((err) => {
console.log(err);
});
});
app.get("/", (req, res, next) => {
console.log("the / route");
res.send("<h1>Hello to NodeJS</h1>");
});
app.listen(5003);
My DBUtils
const config = {
user: "sa",
password: "123",
server: "DESKTOP-7KGJI7L", // You can use 'localhost\\instance' to connect to named instance
database: "java",
options: {
encrypt: false,
},
};
const getNameList = (sql) => {
let nameList = "";
let errorString = "";
// Create connection
sql.connect(config, function (err) {
// Err
if (err) {
console.log(err);
}
// Create Request object
let sqlRequest = new sql.Request();
// QueryString
let queryString = `select * from NAME`;
// Run the query
sqlRequest.query(queryString, (err, data) => {
if (err) console.log(err);
//console.log(data); //data.recordset(array)[index].name
data.recordset.forEach((el) => {
nameList += `<li>${el.name}</li>`;
});
return nameList;
});
});
};
exports.getNameList = getNameList;
I pretty sure something wrong in Promise line but don't know how to fix it. Any suggest?
I think you are a newbie in Nodejs You made a common mistake. You did not use promise pattern correctly. Also, no need to pass next callback unless required.
Change getNameList as below :
const getNameList = (sql) => {
let nameList = "";
let errorString = "";
// Create connection
return new Promise (function(resolve,reject) {
sql.connect(config, function (err) {
// Err
if (err) {
console.log(err);
reject(err)
}
// Create Request object
let sqlRequest = new sql.Request();
// QueryString
let queryString = `select * from NAME`;
// Run the query
sqlRequest.query(queryString, (err, data) => {
if (err) {console.log(err)
reject(err)
}
//console.log(data); //data.recordset(array)[index].name
data.recordset.forEach((el) => {
nameList += `<li>${el.name}</li>`;
});
resolve(nameList);
});
});
})
};
Change app.get("/all") as below:
app.get("/all", (req, res) => {
DBUtils.getNameList(sql).then(function(list) {
res.status(200).send(list)
}).catch(function(err) { //handle error here
res.status(500)
})
})
Moreover, learn how to use promises and async-await.
Use appropriate body-parser as per requirement ie json, text etc.
Learn how and when to use next

How can i access nested promise data?

I am trying to set up a route that sends data from a nested promise to my vue app.
But i'm having trouble with the getting data from the nested promises.
i tried using a callback with no success
app.get('/notification', (req, res) => {
const getData = (data) => {
console.log(data)
}
scheduler(data)
})
const scheduler = (callback) => {
sftp
.connect({ credentials })
.then(() => {
return sftp.list(root);
})
.then(async data =>
{
const filteredFile = data.filter(file => {
let currentDate = moment();
let CurrentTimeMinusFive = moment().subtract(5, "minutes");
let allAccessTimes = file.accessTime;
let parsedAccessTimes = moment(allAccessTimes);
let filteredTime = moment(parsedAccessTimes).isBetween(
CurrentTimeMinusFive,
currentDate
);
return filteredTime;
});
for (const file of filteredFile) {
let name = file.name;
let filteredThing;
await sftp
.get(`Inbound/${name}`)
.then(data => {
csv()
.fromString(data.toString())
.subscribe(function (jsonObj) {
return new Promise(function (resolve, reject) {
filteredThing = new Notification(jsonObj);
filteredThing.save()
.then(result => {
console.log(result);
callback(result) **// THIS IS THE RESULT I NEED IN MY FRONT END**
})
.catch(err => {
console.log(err);
});
resolve();
});
});
});
}
})
When i go to localhost/notification i get:
ReferenceError: data is not defined
Thanks in advance!

Avoiding callback hell

I have this code that serves every markdown file in the './markdown' folder. At '/api/markdown/filename'.
var apiRouter = express.Router();
markdownFolder = './markdown/';
apiRouter.get('/:markdown_file_noext', function(req, res) {
fs.readdir(markdownFolder, function(err, markdown) {
if (err) throw err;
markdown.forEach(function(file) {
fs.readFile(markdownFolder + file, 'utf8', function(err, file_content) {
if (err) throw err;
fileNoExtension = file.slice(0, file.indexOf('.'));
if (req.params.markdown_file_noext == fileNoExtension) {
res.json({
'title': fileNoExtension,
'markdown': marked(file_content)
});
};
});
});
});
});
But i end having a ton of callbacks do the the nature of the 'fs' methods. How do i avoid this?
Using Q as promise library:
const Q = require('q');
const fs = require('fs');
const markdownFolder = './markdown/';
const readdir = Q.nfbind(fs.readdir);
const readFile = Q.nfbind(fs.readFile);
readdir(markdownFolder).then(markdown => {
const promises = [];
markdown.forEach(file => promises.push(readFile(markdownFolder + file, 'utf8')));
return Q.all(promises);
}).then(files => {
// Do your magic.
}).catch(error => {
// Do something with error.
});
You have different option.
Use named Function instead of anonymus functinos. It would make it a little bit more readable but you will still be using callbacks.
Use Promises, but you will need to use bluebird to wrap the fs module.
For a more advance option, you can use generators and Promises to make your code look more like a sync way. Take a look at co or bluebird.coroutine.
With Promises you could do like this:
const path = require('path');
var apiRouter = express.Router();
markdownFolder = './markdown/';
apiRouter.get('/:markdown_file_noext', function(req, res) {
readdir(markdownFolder)
.then((files) => {
const tasks = files.map((file) => {
const filePath = path.resolve(markdownFolder, file);
return readFile(filePath);
});
return Promise.all(tasks); // Read all files
})
.then((fileContents) => {
return fileContents.map((content) => {
fileNoExtension = file.slice(0, file.indexOf('.'));
if (req.params.markdown_file_noext == fileNoExtension) {
return {
'title': fileNoExtension,
'markdown': marked(content)
};
};
})
})
.then((results) => {
// It's better if you aggregate all results in one array and return it,
// instead of calling res.json for each result
res.json(results);
})
.catch((err) => {
// All errors are catched here
console.log(err);
})
});
function readdir(folderPath) {
return new Promise((resolve, reject) => {
fs.readdir(folderPath, (err, files) {
if (err) {
return reject(err);
}
resolve(files);
});
});
}
function readFile(filePath) {
return new Promise((resolve, reject) => {
fs.readFile(filePath, 'utf8', (err, file_content) => {
if (err) {
return reject(err);
}
resolve(file_content);
});
});
}

Resources