Insert email with unique id node js - mysql

How am I working with nodejs, mysql, forEach trying to save the email in my DB with a unique id, using the textarea tag, based on this question
Insert multiple email to mysql using single textarea
For-each over an array in JavaScript
javascript split on non-alphanumeric an keep delemiters at start
<form class="" action="/registration/instudent/{{id_school}}/{{mat}}/{{grade}}" method="post">
<textarea name="email" ></textarea>
<button class="btn btn-lg">Save</button>
</form>
Using the example in PHP base, in my example.js file I have this code, try to save all three variables.
router.post('/instudent/:id_school/:mat/:grade', isLoggedIn, async (req,res) => {
const { id_school, mat, grade } = req.params;
const { email } = req.body;
var uStudent = {
id_school,
mat,
grade,
email
}
Object.keys(uStudent).forEach(function (key){
console.log(uStudent[key]);
db.query('INSERT INTO date set ?', uStudent);
});
//res.redirect('/');
});
When saving to my database, incorrectly insert the texts.
In my database it inserts me in this way.
Any guide to see what I am doing wrong and that every email in the textarea tag gets a unique id?
correct form

I can't find where in the code you are setting the email value to be save.
there are some question here:
You are looping base on your object keys(is this the correct behavior)?
where did you update the uStudent to update its email?
I think you should loop based on splitted email:
router.post('/instudent/:id_school/:mat/:grade', isLoggedIn, async (req,res) => {
const { id_school, mat, grade } = req.params;
const { emails } = req.body;
const uStudent = {
id_school,
mat,
grade
};
// loop base on email
let _emails = emails.split(/\r?\n/);
_emails.forEach(email => {
// update uStudent email field
uStudent.email = email;
// insert the uStudent
db.query('INSERT INTO date set ?', uStudent);
});
});

Related

Edit form that is pre-filled with API data - React

I am building a form that is pre-populated by the results of an axios get request to a nodejs API that returns an array (stored in MySQL). I asked this question yesterday, implemented a solution that was provided and it worked. The next day I tested it thoroughly and it turns out that on submission only the edited fields were passed but not the values from the unedited fields.
I can get the data to map onto the form, but i cannot edit the form. The idea is for it to be an "edit user" form. I suspect the issue is in the onChange portion of the input field.
The form is accessed from a table that is also mapped with the results of a get request. Upon clicking the edit button, the userID from the table row is passed to the edit form through useNavigate and useLocation (I can add this portion of code if needed).
Backend
Here is the API controller that queries the MySQL database and then sends to the frontend:
export const edit = async (req, res) => {
db.query(
"SELECT * FROM userIndex WHERE userID = ?",
[req.params.userID],
(err, rows) => {
if (!err) {
res.send(rows);
} else {
console.log(err).res.send({ alert: err });
}
}
);
};
Here's an example result of the query above:
[
{
"userID": 143,
"firstName": "Kenan",
"lastName": "Erasmus",
"role": "student",
"email": "kenan#gmail.com",
"password": "$2b$12$v3s0D6cNkGwM3/IWXPdv..TRfRZLmDNuZBfrWlUCt4vKnyRi75jWe",
"createdAt": "06/10/2022, 13:56:51",
"updatedAt": "07/10/2022, 19:45:46",
"lastLogin": null
}
]
Frontend
Here is the portion of code that performs the request to the API:
useEffect(() => {
const config = {
headers: { "x-auth-token": token },
};
const fetchData = async () => {
const results = await api.get("/users/edituser/" + userID, config);
setRows(results.data);
setFirstName(rows.firstName)
};
fetchData();
}, [setRows, userID, token]);
State for "rows" (set on API response):
const [rows, setRows] = useState([]);
const [firstName, setFirstName] = useState("");
And finally, an example input field:
<input
type="text"
className="form-control"
id="inputEmail4"
placeholder="First Name"
name="firstName"
value={firstName}
onChange={(e) => setFirstName(e.target.value)}
></input>
I have only included the "firstName" input as an example. In total, this form has about 6 fields.
I would greatly appreciate any assistance with this. Let me know if I can supply any more code.
Found a workaround that seems quite logical to me. I initialised new blank states for each of the input fields
const [firstName, setFirstName] = useState("");
Then mapped the form with "rows" and set each field value to its correspond state (as seen in the useEffect below)
Frontend useEffect:
useEffect(() => {
const config = {
headers: { "x-auth-token": token },
};
const fetchData = async () => {
const results = await api.get("/users/edituser/" + userID, config);
setRows(results.data);
setFirstName(results.data[0].firstName);
setLastName(results.data[0].lastName);
setEmail(results.data[0].email);
setPassword(results.data[0].password);
setRole(results.data[0].role);
};
fetchData();
}, [setRows, userID, token]);
Example input field:
<input
type="text"
className="form-control"
id="inputEmail4"
placeholder="First Name"
name="firstName"
value={firstName}
onChange={(e) => setFirstName(e.target.value)}
></input>
By doing it this way, the form maps through "rows", and then each input field immediately gets a new state once typing occurs.
I know it's ugly, but it is effective. I'm new to coding so I don't know all the ins and outs of React yet - but this solution works for me. Hope this helps anyone looking for a solution to the same issue!

React wait for function to finish?

I want to create a form where I type some data (barcode and name) and if an object with this data exists in my Products table I set states and save it in another Stocks table. But I have a problem when an objects doesn't exist. First I want to post it to a Products table and then to a target table. When I set product_id it is only visible in my saveProduct function and object is added to Stocks with id one down.
I tried also setting id in saveStocks() but it doesn't work because it is called before Products table is updated.
How to wait for it to finish? Or how to set id properly?
const saveProducts = () => {
var data = {
barcode: barcode,
name: name,
};
axiosInstance.post('/products/', data)
.then(response => {
setBarcode(response.data.barcode);
setName(response.data.name);
setProductId(response.data.product_id) //doesn't update in second function
})
.catch(e => {
console.log(e);
});
}
const saveStock = () => {
const temp = products.filter(product => product.barcode == barcode)
if (!temp.length) {
saveProducts()
getProducts()
setProductId(products[products.length-1].product_id) //called before saveProducts()
}
setTimeout(() => {
var data = {
stock_id: stock_id,
product_id: product_id,
count: count,
};
axiosInstance.post('/stocks/', data)
.then(response => {
setStockId(response.data.stock_id);
setProductId(response.data.product_id);
setCount(response.data.count);
})
.catch(e => {
console.log(e);
});
}, 2000)
}
I call saveStock() when clicking the button under my form:
<button className="btn btn-success" type="button" onClick={saveStock}>Add</button>
Why can't you have a separate button disable state which needs to be disabled untill saveProducts post response is back. Then you can enable it to use Add button. Then again, once you execute saveStock successfully, you can disable it again which disable the Add button.
You need to create a variable that you can await and then reference before running your second API call. For example:
let products = await saveProducts();
if (products) {
saveStock();
}

Getting error when printing json array in EJS variable on console

Guys I am using expressjs, ejs to develop an online shopping website.
Scenario
In order to display products {name, description, imageUrl} I am iterating with the help of ejs control-flow on the webpage.
I am sending an array that contains all the details about each product in JSON format. (from server)
on the client-side when I try to access this array of jsons I get the following error.
(index):266 Uncaught SyntaxError: Invalid or unexpected token
When I opened the sources tab in google chrome it, showed me this
At line number 266. I believe that it is taking this as a string by wrapping the array in double quotes.?
Could anyone tell me what's going wrong with this code?
And by the way, is how I trying to print the array on chrome console
<script>
const data = JSON.parse("<%- products %>");
console.log(data);
</script>
where products are an array of jsons
Backend home route which is sending the JSON array is as follows
router.get("/", async (req, res) => {
let catalogInformation = {};
//getAllProducts returns array of json from the database
const products = await getAllProducts();
catalogInformation.products = products;
userData = {
email: null,
username: null,
};
catalogInformation.userData = userData;
if (req.session.userInformation != null || req.session.userInformation != undefined) {
catalogInformation.userData = req.session.userInformation;
} else {
catalogInformation.userData = {
email: null,
username: null,
};
}
// res.render("catalog", userData);
res.render("catalog", catalogInformation);
return;
});
getAllProducts() method
const getAllProducts = async () => {
const Product = mongoose.model("product", productSchema);
const allProducts = await Product.find();
return allProducts;
};
You don't need to use JSON.parse. Just output the JSON directly:
var data = <%- products %>;
I wouldn't suggest making an AJAX call because you'd be handling 2 requests instead of 1.

How to save & retrive image to/from mysql?

Two part quersion.
Part 1:
Im uploading an image to my server and want to save it to my database.
So far:
table:
resolver:
registerPhoto: inSequence([
async (obj, { file }) => {
const { filename, mimetype, createReadStream } = await file;
const stream = createReadStream();
const t = await db.images.create({
Name: 'test',
imageData: stream ,
});
},
])
executing query:
Executing (default): INSERT INTO `images` (`Id`,`imageData`,`Name`) VALUES (DEFAULT,?,?);
But nothing is saved.
Im new to this and im probably missing something but dont know what.
Part2:
This is followed by part 1, lets say I manage to save the image, how do I read it and send it back to my FE?
An edit: Ive read alot of guides saving the an image name to the db and then tha actuall image in a folder. This is NOT what im after, want to save the image to the DB and then be able to fetch it from the DB abd present it.
This took me some time but I finaly figured it out.
First step (saving to the db):
Have to get the entire stream data and read it like this:
export const readStream = async (stream, encoding = 'utf8') => {
stream.setEncoding('base64');
return new Promise((resolve, reject) => {
let data = '';
// eslint-disable-next-line no-return-assign
stream.on('data', chunk => (data += chunk));
stream.on('end', () => resolve(data));
stream.on('error', error => reject(error));
});
};
use like this:
const streamData = await readStream(stream);
Before saving I tur the stream into a buffer:
const buff = Buffer.from(streamData);
Finaly the save part:
db.images.create(
{
Name: filename,
imageData: buff,
Length: stream.bytesRead,
Type: mimetype,
},
{ transaction: param }
);
Note that I added Length and Type parameter, this is needed if you like to return a stream when you return the image.
Step 2 (Retrieving the image).
As #xadm said multiple times you can not return an image from GRAPHQL and after some time I had to accept that fact, hopefully graphql will remedy this in the future.
S What I needed to do is set up a route on my fastify backend, send a image Id to this route, fetch the image and then return it.
I had a few diffirent approaches to this but in the end I simpy returned a binary and on the fronted I encoded it to base64.
Backend part:
const handler = async (req, reply) => {
const p: postParams = req.params;
const parser = uuIdParserT();
const img = await db.images.findByPk(parser.setValueAsBIN(p.id));
const binary = img.dataValues.imageData.toString('binary');
const b = Buffer.from(binary);
const myStream = new Readable({
read() {
this.push(Buffer.from(binary));
this.push(null);
},
});
reply.send(myStream);
};
export default (server: FastifyInstance) =>
server.get<null, any>('/:id', opts, handler);
Frontend part:
useEffect(() => {
// axiosState is the obj that holds the image
if (!axiosState.loading && axiosState.data) {
// #ts-ignore
const b64toBlob = (b64Data, contentType = '', sliceSize = 512) => {
const byteCharacters = atob(b64Data);
const byteArrays = [];
for (let offset = 0; offset < byteCharacters.length; offset += sliceSize) {
const slice = byteCharacters.slice(offset, offset + sliceSize);
const byteNumbers = new Array(slice.length);
// #ts-ignore
// eslint-disable-next-line no-plusplus
for (let i = 0; i < slice.length; i++) {
byteNumbers[i] = slice.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
byteArrays.push(byteArray);
}
const blob = new Blob(byteArrays, { type: contentType });
return blob;
};
const blob = b64toBlob(axiosState.data, 'image/jpg');
const urlCreator = window.URL || window.webkitURL;
const imageUrl = urlCreator.createObjectURL(blob);
setimgUpl(imageUrl);
}
}, [axiosState]);
and finaly in the html:
<img src={imgUpl} alt="NO" className="imageUpload" />
OTHER:
For anyone who is attempting the same NOTE that this is not a best practice thing to do.
Almost every article I found saved the images on the sever and save an image Id and other metadata in the datbase. For the exact pros and cons for this I have found the following helpful:
Storing Images in DB - Yea or Nay?
I was focusing on finding out how to do it if for some reason I want to save an image in the datbase and finaly solved it.
There are two ways to store images in your SQL database. You either store the actual image on your server and save the image path inside your mySql db OR you create a BLOB using the image and store it in db.
Here is a handy read https://www.technicalkeeda.com/nodejs-tutorials/nodejs-store-image-into-mysql-database
you should save the image in a directory and save the link of this image in the database

Firebase Updating User Data With Custom Fields After Creating User

I want to update the newly created User's data. The returned JSON is:
{
"user":{
"uid":"test123",
"displayName":null,
"photoURL":null,
"email":"test12#test.com",
"emailVerified":false,
"phoneNumber":null,
"isAnonymous":false,
"tenantId":null,
"providerData":[
{
"uid":"test12#test.com",
"displayName":null,
"photoURL":null,
"email":"test12#test.com",
"phoneNumber":null,
"providerId":"password"
}
],
"apiKey":"test123",
"appName":"[DEFAULT]",
"authDomain":"test123.firebaseapp.com",
"stsTokenManager":{
"apiKey":"test123",
"refreshToken":"test123",
"accessToken":"test123",
"expirationTime":1571238989357
},
"redirectEventId":null,
"lastLoginAt":"1571235389108",
"createdAt":"1571235389108"
},
"credential":null,
"additionalUserInfo":{
"providerId":"password",
"isNewUser":true
},
"operationType":"signIn"
}
This is my callout and update:
createUser = async (userData) => {
return await firebase.auth().createUserWithEmailAndPassword(userData.get('userName'), userData.get('password'))
.then((authData) => {
firebase.database().ref('users/' + authData.user.uid + '/').set({
fullName: userData.get('fullName'),
pictures: userData.get('pictures'),
phoneNumber: userData.get('phoneNumber')
});
})
};
Is it possible to add to the User table custom fields?
A few things are happening. It appears that userData can not be seen in the .then statement. So to solve this I attempted to pass in the userData JSON as a param. This did not work. I then broke out each value out of userData, saved it into a const and passed that value. This did not work.
I can see that userData has values in it before the .then statement. I am able to successfully create a new user with the right userName and password. This means to me either:
A - I am not passing the userData JSON correctly or
B - I am not allowed to pass data to firebase like I am doing
My end goal is to sign up a user and then take all of the data they input from a registration form (aka userData) and update the user table with it.
Articles I am using are:
https://firebase.google.com/docs/auth/web/manage-users
https://medium.com/mindorks/firebase-realtime-database-with-react-native-5f357c6ee13b
Main class that calls the createUser function:
const signUp = (dispatch) => {
return async (userData)=>{
try{
const response = await config.createUser(userData);
console.log('sign up resonse1: ' + response); //coming back as undefined
//todo:: figure out how to parse out the apikey out of response
await AsyncStorage.setItem('token', '123mockToken');
dispatch({type: 'sign_up', payload: '123mockToken'});
navigate('mainFlow');
} catch(e){
dispatch({type: 'add_error', payload: '' + e}); //we call dispatch anytime we want to update our state
}
}
};
I understand that the parameter userData holds all the data you want to use for creating the user ("all of the data they input from a registration form").
The following should work:
createUser = async userData => {
try {
const userCredential = await firebase
.auth()
.createUserWithEmailAndPassword(
userData.get('userName'),
userData.get('password')
);
const userId = userCredential.user.uid;
await firebase
.database()
.ref('users/' + userId + '/')
.set({
fullName: userData.get('fullName'),
pictures: userData.get('pictures'),
phoneNumber: userData.get('phoneNumber')
});
return userId; //As per your comment below
} catch (error) {
return error;
}
};
The createUserWithEmailAndPassword() method returns a UserCredential which contains a User.