Exporting data from the function [mysql, node.js, discord.js] - javascript

I have such a problem here with exporting data from functions. I do not know if it can be done at all, but I do not see any other solution here. My problem is that I am exporting a function and I would like to export the result of this function, so in this case I have MYSQL. I cannot add rows to module.exports = {sql, rows} because I get a message that rows is undefined. I am asking for help or for some other solution.
//------------------------------
📁 index.js
//------------------------------
const mysql = require('mysql')
const db = require('./database')
var con = mysql.createConnection({
host: db.host,
user: db.user,
password: db.password,
database: db.database
})
con.connect(err => {
if(err) console.log(err)
})
function sql(sql){
con.query(sql, (err, rows) => {
if(err) console.log(err)
})
}
module.exports = { sql, rows }
// con.end()
//------------------------------
📁 Command file
//------------------------------
const sql = require('./../config/test')
sql.sql("SELECT * FROM `servers`")
console.log(sql.rows)
//------------------------------
📁 Console error
//------------------------------
(node:30132) UnhandledPromiseRejectionWarning: ReferenceError: rows is not defined

You can make use of a Callback function in which you can use the data how you want. By passing a function as a parameter to the sql function, you can invoke that callback function with the rows fetched from the database as a parameter.
Take a look at the code I edited for you:
Your index.js
/* Skipped all code above that isn't important for this example */
function sql(query, callback){
con.query(query, (err, rows) => {
if(err) console.log(err);
callback(rows);
});
}
module.exports = {sql}
Your Command file
const queryHandler = require('./../config/test');
// Call the sql function and pass a callback as the 2nd parameter
queryHandler.sql("SELECT * FROM `servers`", (rows) => {
// Do whatever you want with the rows
console.log(rows);
});
Give it a try and see how it goes

Related

Mongodb returns an empty array while retrieving data through nodejs

let mongodb = require('mongodb').MongoClient;
let express = require("express")
let app = express()
let connectionString = 'mongodb://ToDoAppUser:ToDoAppUserPassword#ac-u9kgapm-shard-00-00.8rdkdoi.mongodb.net:27017,ac-u9kgapm-shard-00-01.8rdkdoi.mongodb.net:27017,ac-u9kgapm-shard-00-02.8rdkdoi.mongodb.net:27017/?ssl=true&replicaSet=atlas-68qno6-shard-0&authSource=admin&retryWrites=true&w=majority'
let db
mongodb.connect(connectionString,function(err,client){
if (err) throw err
db = client.db()
app.listen(3000)
console.log("Database connected.");
})
app.use(express.urlencoded({extended : false}))
Trying to retrieve data from MongodB
As you can see that , I am trying to retrieve data from MongoDB collection named #item and want to print it. But it shows an empty array. I am stuck on this. kindly help me to resolve this issue.
app.get("/", function(req, res){
**// this collectio method of mongodb returns empty array.
// however, mongodb got connected, but i cannot retreive data from mongodb**
db.collection('items').find().toArray(function(err, items) {
if(err) console.log(err)
console.log(items)
})
You need to use the following format.
async function findOneListingByName(client, nameOfListing) {
const result = await client.db("sample_airbnb").collection("listingsAndReviews").findOne({ name: nameOfListing });
if (result) {
console.log(`Found a listing in the collection with the name '${nameOfListing}':`);
console.log(result);
} else {
console.log(`No listings found with the name '${nameOfListing}'`);
}
}
This code above is worked for me.
By the way, you can read their documentation here for more examples:
https://www.mongodb.com/developer/languages/javascript/node-crud-tutorial/
My guess is that the call to fetch items from DB is asynchronous, and you're trying to use items synchronous manner.
Try adding async to the controller function and using await for the DB request. Like this:
app.get("/", async function(req, res){
/* Mongo documents don't show any parameters for the toArray method
* Read here https://www.mongodb.com/docs/manual/reference/method/cursor.toArray/#mongodb-method-cursor.toArray
*
*/
const itemsFromDB = await db.collection('items').find().toArray()
conssole.log('items are:' itemsFromDB )
})

SQL to MongoDB Migration using nodejs script

Im new to nodejs and Im currently doing an sql to mongodb migration. I have created a script to load data to mongodb from sql queries. I created the script with the sample code from Google and it is working. But im facing below issue and need a workaround for this.
I have an sql query array and I don't need to run those queries if any of the queries has any syntax issues or any errors in the query result. (Say if the second query has syntax issue then no need to load the data of first query to mongo, currently its loading in my case). Basically if any of the query has any issue then no need to load the result in the mongo collection. And also if any issues from the mongo side no need to commit the transactions.
I have used the mongo transactions here to roll back the data if any errors. please find the below code and any help would be much appreciated.The sql and mongo credentials are mock data only.
config file code
var mongoCollection = 'collectionName';
exports.mongoCollection = mongoCollection;
var queryList = [
'sample query one',
'sample query two '
];
exports.queryList = queryList;
main script code
var MongoClient = require('mongodb').MongoClient;
var sql = require('mysql');
const config = require('./assets/config');
var sqlConfig = {
user: 'username',
password: 'password',
server: 'servername',
database: 'databasename',
port: 'portname',
multipleStatements: true
};
async function transaction() {
const mongodbUrl = 'mongourl';
const client = await MongoClient.connect(mongodbUrl, {useNewUrlParser: true}, {useUnifiedTopology:
true});
const db = client.db();
config.queryList.forEach(query => {
new sql.ConnectionPool(sqlConfig).connect().then(pool => {
return pool.request().query(query)
}).then(result => {
(async()=>{
const session = client.startSession();
session.startSession({
readConcers: {level: 'snapshot'},
writeConcern: {w: 'majority'}
});
try {
const collection = client.db('mongodbName').collection(config.mongoCollection);
await collection.insertMany(result.recordset, {session});
await session.commitTransaction();
session.emdSession();
console.log('transaction completed');
}catch(error){
await session.abortTransaction();
session.endSession();
console.log('transaction aborted');
throw error;
}
});
sql.close();
}).catch(error => {
sql.close();
throw error;
})
});
};
transaction();
Depending on the volume of data, you might look at breaking the process into two parts
Get the data from mySql
If no errors, load into Mongo
That would save you having to roll back the mongo writes
You can also take advantage of the default mongo pool size (5) and use pool on the mySQL side too.
Currently, this code is creating a pool for every select, which isn't optimal
config.queryList.forEach(query => {
new sql.ConnectionPool(sqlConfig).connect().then(pool => {//<-New pool per query?
return pool.request().query(query)
})
})
Instead, you can set up a pool once, per the mySql documentation
It looks like that driver only has a callback api, but you can promisfy the query to make it easier to work with.
So to put it all together, you could try something like this (this isn't working/tested code, just a suggestion)
var MongoClient = require('mongodb').MongoClient;
var sql = require('mysql');
const config = require('./assets/config');
var pool = sql.createPool({
connectionLimit : 5,
host : 'servername',
user : 'username',
password : 'password',
database : 'databasename'
});
async function transaction() {
try{
const mongodbUrl = 'mongourl';
const client = await MongoClient.connect(mongodbUrl, {useNewUrlParser: true}, {useUnifiedTopology: true});
const db = client.db();
const collection = client.db('mongodbName').collection(config.mongoCollection);
//Map your query list to an array of runSql promises
//this will complete when all queries return, and jump to the catch if any fail
let results = await Promise.all(config.queryList.map(runSql))
//Map the results to an array of mongo inserts
let inserts = await Promise.all(results.map(r=>collection.insertMany(r.recordset)))
//Close all connections
pool.end((err)=>err?console.err(err):console.log('MySQL Closed'))
client.close((err)=>err?console.err(err):console.log('MongoDB Closed'))
}
catch(err){
console.error(err)
}
};
transaction();
function runSql(queryStr){
return new Promise((resolve, reject)=>{
pool.query(queryStr, function (error, results, fields){
error?reject(error):resolve(results)
})
})
}
If data volume is a concern, you might want to look at getting streams from your mySql selects instead of just running them

Node.js global variable only works once

I have a global variable in my server side code inside a post route and i am trying to access it within another post route. The code executes perfectly when the second post route is called for the first time, but when the second post route is triggered a second time, the value of the global variable becomes undefined.
Snippet of first post route that declares the global variable:
app.post("/login", function(req, res) {
...
fs.readFile('results.json', function (err, data) {
if(err){
console.log(err)
} else{
var json = JSON.parse(data)
...
global.Identifier;
global.Identifier = Identifier;
return global.Identifier;
}
}
);
res.redirect("/");
});
snippet of second post request that accesses global variable:
app.post("/addtask", function(req, res) {
var gloablIdentifier = global.Identifier;
...
res.redirect("/");
};
(When the second post request is accessed a second time, the value of gloablIdentifier = undefined )
NOTE: I understand that using global variables is VERY BAD PRACTICE and should be avoided in most situations at all costs, but I would still like to work on this problem.
Thanks in advance
You did not wait readFile has to be finished and return response. Since, fs.readFile is async, global.Identifier will update later. You can await to read the file and then return;
app.post("/login", function(req, res) {
fs.readFile("results.json", function(err, data) {
if (err) {
console.log(err);
} else {
var json = JSON.parse(data);
global.Identifier = Identifier;
return global.Identifier;
}
// wait for read file
res.redirect("/");
});
// res.redirect("/");
});
async-await version:
const { promisify } = require("util");
const readFile = promisify(fs.readFile);
app.post("/login", async function(req, res) {
try {
const data = await readFile("results.json");
var json = JSON.parse(data);
global.Identifier = Identifier;
return res.redirect("/");
} catch (error) {
return res.redirect("/");
}
});
From the looks of it, you are using something like Express.
Even though this might be a bad practice I think that you should give a try to using the set functionality provided by express itself.
As such, in your app.js do it like this:
app.set("identifier", Identifier)
Then, in your routes:
app.post("/addtask", function(req, res) {
var gloablIdentifier = app.get('identifier')
...
res.redirect("/");
};
I did not test this, it's based on the documentation and on this answer
EDIT: I tested this and it works. Also, to change the variable again just do this on your route:
app.set('identifier', newValue)
I hope the answer is complete now!

mongo database doesn't show up in command line

I don't understand why my mongo db isn't showing up when I run "show databases" in the command line. I see other mongo db's I created in the past, but not the current one. Here is my code: (using mongoose ORM):
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/fuelTracker');
var Schema = mongoose.Schema;
var fuelSchema = new Schema({
time : { type : Date, default: Date.now },
miles : Number,
gallons: Number
});
var FuelStop = mongoose.model('FuelStop', fuelSchema);
module.exports = FuelStop;
And where I'm attempting a basic model.save operation:
app.post('/', function (req, res ) {
results = req.body;
var fuelStop = new FuelStop (results)
fuelStop.save(function() {
console.log('record saved to monogoDB');
});
})
Any clue as to why my 'fuelTracker' database doesn't appear in the command line when I run 'show databases' within mongo?
THANK YOU!!
did you try show dbs? show databases print all databases available, see the doc here: https://docs.mongodb.com/manual/reference/mongo-shell/
The database doesn't get created until you insert data into a collection in the database.
I tested your code by creating and running a script to seed the fuelTracker database with example JSON data. I then ran show databases and was able to see fuelTracker listed.
If you would like to try this, in a new file seed.js:
const db = require('./fileName.js');
const fs = require('fs');
let fuelData = fs.readFileSync('./data.json', 'utf8', (err, data) => {
if (err) throw err;
console.log(data);
});
let jsonFuel = JSON.parse(fuelData);
db.remove({}, () => {
console.log('Successfully removed fuel data');
db.collection.insert(jsonFuel, (err, docs) => {
if (err) {
console.log(`error inserting data: ${err}`);
} else {
console.log(`Fuel data was stored: ${docs}`);
}
});
});
Then create example data in data.json:
[
{
"time":"04/18/2018",
"miles":"28",
"gallons":"30"
}
]
Then run your seed file and your database should hopefully be showing up.

Why doesn't push move results from DB query into variable?

Intent
Establishing a connection with a DB in my route, running a query, capturing the result, and making it accessible to my index view to render in the DOM.
Problem
DB connects and returns results successfully in the console. However, fails to push this result into the "finalResult" array.
var express = require('express');
var router = express.Router();
router.get('/', function(req, res) {
// Establish Connection with Database
var mysql = require('mysql');
var connection = mysql.createConnection({
host : '127.0.0.1',
user : 'root',
password : 'xxxxxxx',
database : 'my_db'
});
connection.connect();
// // Query and post result to console
connection.query('SELECT * FROM products', function(error, results, fields) {
if (error) throw error;
doSomething(results[0]);
});
connection.end();
var finalResult = ['hello'];
function doSomething(results) {
console.log(results.name);
finalResult.push(results.name);
}
console.log(finalResult);
// Render/make accessible to views
res.render('index', {
pageTitle: 'Home',
result: finalResult
});
});
module.exports = router;
doSomething(results[0]); successfully pushes the result into the doSomething() function because console.log(results.name) returns the correct query result. Issue occurs with finalResult.push(results.name) because console.log(finalResult) only returns an array with "hello" when it should have "hello" plus the query result.
Please note when you query database from mysql module is synchronous (the query takes function as argument -- callback). That's mean you cannot take result value as variable outside the query function. Try to use async/await or promise to get returned value.
Try to write console.log(finalResult) inside doSomething function, after you pushed the new data to finalResult array.
I think that you see only "helo" because console.log(finalResult) execute before the doSomething function finished (before you add the data to finalResult array).

Categories