How to convert MySql Buffer to Image in React/Node/Express - mysql

I need help to convert a buffer to a base64 using Node and React.
I'm posting an image with an input to my databse and I'm not sure I'm doing it right. This is my first time doing this. Is there something missing here? Back-end POST request:
app.post("/api/img", (req, res) => {
const productimg = req.body.productimg;
const sqlInsert = "INSERT INTO users_files (file_src) VALUES (?)";
db.query(sqlInsert, [productimg], (err, result) => {
console.log(result);
})
})
In the database the image is a blob, and then with the GET request I get the image as a buffer. This is the GET request in the front-end:
useEffect(() => {
Axios.get('http://localhost:3001/api/get/img').then((base64String) => {
setBackenddata(base64String.data)
var blob = new Blob(productImg[0]?.file_src, {
type: "image/jpg",
});
var reader = new FileReader();
reader.readAsDataURL(blob);
reader.onloadend = function () {
let base64String = reader.result;
setProductImg(base64String);
};
console.log(base64String)
})
}, [])
And this is the get function in the back-end:
app.get('/api/get/img', (req, res) => {
const sqlGet = "SELECT * FROM users_files";
db.query(sqlGet, (err, result) => {
res.send(result);
})
})
This is what I get from the base64String:
The base64String does not seem to do anything, since it is still type: buffer.
In the back end I have tried with a Multer, but that did not work. I've been trying with different things in the back-end and the front-end, but since I'm new to this it is hard to know what's wrong.

Related

How to add columns to database results in nodejs

I'm using nodejs with mysql and fs to query a database and modify the results by adding a text file to each row. I realize I need to use a promise here but I can't quite get it. I can't figure out what I'm doing wrong. Here is my code so far:
db.query(sql, params, function(err, rows) {
if(err) {
res.status(400).json({"error": err.message});
return;
}
var data = {};
var p = new Promise(function(resolve, reject) {
rows.forEach(function(row) {
var filePath = `${contentdir}/${row.strTicketNumber}-${row.strTicketRevision}.txt`;
row.fileTxt = fs.readFile(filePath, 'utf8', function(error, content) { if(error) return ""; return content; });
data[row.intSerial] = row;
});
resolve(data);
});
p.then(function() {
res.json( data );
})
});
You can save yourself using a Promise here if you struggle with them by using synchronous Node APIs:
db.query(sql, params, function(err, rows) {
if(err) {
res.status(400).json({"error": err.message});
return;
}
var data = {};
rows.forEach(function(row) {
var filePath = `${contentdir}/${row.strTicketNumber}-${row.strTicketRevision}.txt`;
row.fileTxt = fs.readFileSync(filePath, 'utf8');
data[row.intSerial] = row;
});
res.json( data );
});
Note readFileSync instead of readFile
Or, if you really want to use Promises, you can do it like so:
db.query(sql, params, function(err, rows) {
if(err) {
res.status(400).json({"error": err.message});
return;
}
var data = {};
var promises = []
rows.forEach(function(row) {
var filePath = `${contentdir}/${row.strTicketNumber}-${row.strTicketRevision}.txt`;
promises.push(new Promise((resolve, reject) => {
fs.readFile(filePath, 'utf8', (err, content) => {
if (err) reject(err)
row.fileTxt = content
data[row.intSerial] = row
resolve()
});
}))
});
Promise.all(promises).then(() => {
res.json( data );
})
});
The main difference between these snippets is that no. 1 reads each text file one-by-one synchronously, while no. 2 reads them "at the same time" (with a few asterisks :p)
Whether this matters to you will depend on how many files you'll be reading, as well as whether you find it significantly easier to read & maintain the first example until you are more comfortable with Promises.

How do I return files as base-64 data URL strings from my API using MongoDB/GridFS?

I have a collection of Contacts inside my MongoDB
Those Contacts have avatars (or "profile pictures")
Here is the profile picture for the above user:
... and a chunk of that file (there's only one).
I'm trying to take ^^^ that ^^^ chunk and parse it into a base-64 data URL in order to return it from my server back to my application and use it inside an <img>'s src attribute.
app.get('/queryContacts', (req, res) => {
const getContacts = async query => {
let contacts = await db
.collection('contacts')
.find(query)
.toArray();
return contacts;
};
const getImages = async id => {
let imageUrl = 'data:image/jpg;base64';
await bucket
.openDownloadStream(new ObjectID(id))
.on('data', chunk => {
imageUrl += chunk.toString('base64');
})
.on('end', () => {
return imageUrl;
});
}
getContacts({account_id: new ObjectID(req.query.id)}).then(contacts => {
Object.keys(contacts).forEach(key => {
getImages(contacts[key].image_id).then(url => {
console.log(url); // undefined
contacts[key].imageUrl = url;
});
});
res.json(contacts);
});
});
The problem is that when I try this, the URL is undefined because getImages() isn't waiting for the 'end' event to finish.

how to make a post request inside async function?

At the end of the waterfall-dialog in "summary" (i.e., the last if statement) i want to automatically make a post request without making an API call in Postman, is eventListener the way? How to include it?
async summaryStep(step) {
if (step.result) {
// Get the current profile object from user state.
const userProfile = await this.userProfile.get(step.context, new UserProfile());
userProfile.name = step.values.name;
//the same for other step values(email, doctor, date)
let msg = `you want a date with dr. ${userProfile.doctor} , and your name is ${userProfile.name}.`;
if (userProfile.date !== -1) {
msg += `you have an appointment the: ${userProfile.date}.`;
}
await step.context.sendActivity(msg);
let msg1 = `"${userProfile.date}"`;
if (msg1) {
let z = JSON.stringify(userProfile.name);
//and also the other rows to go in the database(email, doctor, date)
var name = JSON.parse(z);
//and also the other rows to go in the database(email, doctor, date)
//this actually works but only if i use postman
var urlencoded = bodyparser.urlencoded({ extended: false });
app.post('/id', urlencoded, (req, res) => {
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
mysqlConnection.query("INSERT INTO users(name, email, doctor, date) VALUES('" + userProfile.name + "','" + userProfile.password + "','" + userProfile.doctor + "','" + userProfile.date + "')", function (err, result, rows) {
if (err) throw err;
console.log("Yeah! record inserted");
console.log(name);
res.send(result);
});
});
const port = process.env.PORT || 8080;
app.listen(port, () => console.log(`Listening on port ${port}..`));
}
} else {
await step.context.sendActivity('Thanks. Your profile will not be kept. Push enter to return Menu');
}
return await step.prompt(CONFIRM_PROMPT3, `is that true? ${step.result}`, ['yes', 'no']);
// this if statement should "fire" the post request...
if (step.result == 'yes') {
return await step.context.sendActivity(`we will contact you soon ${userProfile.password}.`);
}
return await step.endDialog();
}
Per my understanding , you want to know how to call an POST API from Azure bot async function. Pls try the code below in your async summaryStep function to send the post request based on your requirement.
var rp = require('request-promise');
var options = {
method: 'POST',
uri: 'http://localhost:8080/id',
body: {
fieldCount:0,
affectedRows:1,
//your other body content here...
},
json: true,
headers: {
'content-type': 'application/json' //you can append other headers here
}
};
await rp(options)
.then(function (body) {
console.log(body)
})
.catch(function (err) {
console.log(err)
});
}
Hope it helps .
A
nd if there is any further concerns or misunderstand , pls feel free to let me know.
The answer is to move your app.post API endpoint to your index.js file where your bot is already running on a server. Simply spin up a new "server" and "port" making the endpoint available. Then, in your summaryStep (axiosStep in my example), make your API call using Axios, request-promise, or what have you, to post your data. When the API is hit, the data will be passed in and processed.
In the code below, when the API is hit the passed in data is used in a sendActivity posted back to the bot. In your case, your passed in data would be used for the database call in which you could use the returned response in the sendActivity.
Your code would look something like the following. Please note, the post actions are simplified for the sake of the example. You would need to update the post actions to make your mySql queries. This sample also makes use of restify for the server (standard for Bot Framework bots) and uses the same port as the bot, but this can easily be updated to use Express and/or another port.
Hope of help!
index.js
[...]
const conversationReferences = {};
const bodyParser = require('body-parser');
server.post('/id', async (req, res) => {
const { conversationID, data, name } = req.body;
const conversationReference = conversationReferences[ conversationID ];
await adapter.continueConversation(conversationReference, async turnContext => {
var reply = `${ data }. Thanks, ${ name }`;
await turnContext.sendActivity(reply);
});
res.writeHead(200);
res.end();
});
mainDialog.js
async axiosStep ( stepContext ) {
const conversationID = stepContext.context.activity.conversation.id;
try {
const response = await axios.post(`http://localhost:3978/id`, {
data: "Yeah! Record inserted",
name: "Steve",
conversationID: conversationID
})
console.log(response);
} catch (error) {
console.log(error);
}
return stepContext.next();
}

Cannot read property 'findAll' of undefined sequelize

I'm a new learner to express js and sequelizejs. I successfully migrate table in my database so the connection is fine I guess.
Here is my code.
https://github.com/Picks42/express-test
Please review this file
https://github.com/Picks42/express-test/blob/master/models/user.js
Then review this one
https://github.com/Picks42/express-test/blob/master/controller/test.js
Let me know what's the issue.
// all the models using your index.js loader
const models = require('../models');
// the user model, note the capital User since
const M_Bank = models.User;
exports.getTest = function(req,res){
return M_Bank
.findAll()
// don't use M_Bank here since you are getting an array of Instances of the Model
.then(users => res.status(200).send(users))
.catch((error) => {
console.log(error.toString());
res.status(400).send(error)
});
/* this will never execute because it is after the return
exports.index = function (request, response, next) {
response.json((M_Bank.findAll()));
};
*/
};
If you have the option of using async/await it makes for more readable code.
const models = require('../models');
const M_Bank = models.User;
exports.getTest = async function(req, res) {
try {
const users = await M_Bank.findAll();
return res.status(200).send(users);
} catch (err) {
console.log(err.toString());
return res.status(400).send(err);
}
};
You should get rid of the .User field in the 3rd line. because you've exported User itself from the models/user file.
Also, I recommend you not to mess with variables names. M_Bank variable doesn't speak itself
const M_Bank = require('../models/user');
exports.getTest = function(req,res){
return M_Bank
.findAll()
.then(M_Bank => res.status(200).send(M_Bank))
.catch((error) => {
console.log(error.toString());
res.status(400).send(error)
});
exports.index = function (request, response, next) {
response.json((M_Bank.findAll()));
};
};

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.