I have a loop where I am checking if records exist and if not insert it , the problem is my console shows code inside loop doesn't run line by line , it runs all selects first and then run all inserts
loop from excel
tablesdata.map(async function (table) {
check if record exist
await product_meta
.count({
where: [
{
title: fr_name,
language_id: 2,
},
],
})
.then((count) => {
console.log(count);
if (count > 0) {
console.log(count);
} else {
insert record create_pr = products.create(product, {});product_id = create_pr.id;
}
)}
)}
It will be more straightforward to use async/await - the Array.map() is returning an array of promises that can be resolved using Promise.all().
const promises = tablesdata.map(async function (table) {
if (recordExists) {
const count = await product_meta.count({
where: {
title: fr_name,
language_id: 2,
},
});
if (!count) {
// this will create a new product, perhaps it is meant to be a product meta?
const create_pr = await products.create(product, {});
// return the created ID
return create_pr.id;
}
console.log("there are already", count, "product metas");
return null;
}
});
// this will resolve an array of newly created IDs,
const allResults = await Promise.all(promises);
// filter out the null entries
const productIds = allResults.filter((result) => result);
Related
I got my MySQL data printed in console.log() as console.log(result) and it works fine.
Now I need to use this result to define variable MyPlan in a different function.
This is how I got the results from MySQL db:
function load() {
var MySQL = SQL.createConnection(credentials)
MySQL.connect((err) => {
if(err) {
console.log(err);
process.exit(0);
}
for(var i = 0; i < 250; i++) console.log('\n');
console.log('Successfuly logged in!');
});
MySQL.query("SELECT plan FROM users WHERE username = 'asd123'", (err, rows) => {
if(err) { console.log(`[!] SQL Error: ${err}`); return; }
rows.forEach((results) => {
console.log(results); //output: RowDataPacket { plan: 300 }
});
});
}
load();
I need MyPlan: to be declared with a number 300 as stated above.
startMyPlan() {
//var theoric = 10;
this.botCountInt = setInterval(() => {
let json = {
connected: 0,
MyPlan: //300
};
this.send(json);
}, 100);
}
I tried to define results in first function like this:
rows.forEach((results) => {
myresult = results //first option
// OR LIKE THIS:
this.myresult = results; //second option
console.log(results);
});
and write it in startMyPlan() as
let json = {
connected: 0,
MyPlan: this.myresult
};
But first option gave me error myresult is not defined and second option gave me different error: Cannot set properties of undefined(setting 'myresult').
EDIT: I guess my problem is that results won't give me correct output OUTSIDE that function where it's created. It returns undentified when I try to run console.log(results); once it's run outside load() function
So, as per my understanding, you have not defined the myresult variable in any scope.
The first option will work if you do var myresult=undefined just before rows.forEach((results) => call.
One example:
var rows = [{ "test": "foo1" }, { "test": "foo2" }, { "test": "foo3" }, { "test": "foo4" }];
var myresult;
rows.forEach((results) => {
myresult = results //first option
console.log(myresult);
});
console.log(myresult);
I am not sure what exactly you want to do with myresult. But I think above example will be enough to understand things.
I am facing problem while updating multiple rows in table.
following is my data
const update_Data = upins_data.map(
upins_data => [{
upin_id: upins_data.upin_id,
media_type: upins_data.media_type,
land: upins_data.land
}]
);
it has multiple values.
i have tired following code
var updateSecTab = `UPDATE tb_bid_upins SET upin_id=?,media_type=?,land=? WHERE bid_id = ?`;
var query = db.query(updateSecTab,[update_Data,cond],function(error,result,fields){
if (error) { /**If error while inserting into table 2 it rowback the Transaction */
console.log('in err 1');
return db.rollback(function () {
throw err;
});
}
db.commit(function (err, result3) {
if (err) {
console.log('in err 2');
return db.rollback(function () {
throw err;
});
}
/**Send success result to front end */
console.log('success!');
res.send(JSON.stringify(result));
})
});
console.log(query.sql);
When i print the query it gives result as follows
UPDATE tb_bid_upins SET upin_id=('[object Object]'), ('[object Object]'),media_type=1,land=? WHERE bid_id = ?
Hello everyone i have tried following solution and it works.
var upins_data = [ { upin_id: 1, media_type: 5, land: 'Rakhiyal Circle' } ],
[ { upin_id: 3, media_type: 6, land: 'Rakhiyal Circle' } ]
var cond = 1
i have added above two variable in single array as follows
const update_Data = upins_data.map(
upins_data => {
return {
bid_id: cond,
upin_id: upins_data.upin_id,
media_type: upins_data.media_type,
land: upins_data.land
}
}
);
than i have used foreach on update_Data array and i have created multiple sql quires using mysql foramt function.
var queries = '';
update_Data.forEach(function (item) {
let sql = mysql.format("UPDATE tb_bid_upins SET upin_id=?,media_type=?,land=? WHERE bid_id = ? ;", [item.upin_id,item.media_type, item.land, item.bid_id]);
queries += sql;
console.log(sql);
});
than i have passed above queries variable in sql query as follows
db.query(queries,(err,result)=>{
if(err){
console.log('err',err);
}else{
console.log('result',result);
}
});
above code works for me in nodejs .
if anyone wants to improve than they can.
thank you
I used componentDidUpdate and in it I put a shift method, which is used to delete an object from a JSON array and thereby re-render the displayed posts, but the shift method deletes the first object from the array independently in which the delete button on the post will I press? Is there any possibility, then, to bypass the deletion of the first element in favor of the one that is designated to be deleted?
componentDidUpdate(prevProps, prevState) {
const {posts} = this.props;
const indexPosts = posts.findIndex((post) => post.id === this.state.postId);
if(prevProps.posts !== posts){
this.handleData();
} else if (indexPosts !== -1)
{
this.informationAlert();
const log = posts.splice(indexPosts, 1);
console.log(log);
}
}
EDIT: Actions
export const deletedPost = (id) => (dispatch) => {
axios
.delete(`https://jsonplaceholder.typicode.com/posts/${id}`, id, {
headers: {
'Content-type': 'application/json'
}
})
.then((post) =>
dispatch({
type: DELETED_POST,
payload: post.data
})
)
.catch((err) => console.log(err));
};
import { FETCH_POSTS, NEW_POST, DELETED_POST, FETCH_COMMENTS, NEW_COMMENT } from '../actions/types';
const initialState = {
items: [],
item: {},
itemComent: [],
itemNewComment: {},
deletedPost: []
};
export default function (state = initialState, action) {
switch (action.type) {
case FETCH_POSTS:
return {
...state,
items: action.payload
};
case NEW_POST:
return {
...state,
item: action.payload
};
case DELETED_POST:
return {
...state,
deletedPost: action.payload
};
case FETCH_COMMENTS:
return {
...state,
itemComent: action.payload
}
case NEW_COMMENT:
return {
...state,
itemNewComment: action.payload
}
default:
return state;
}
}
EDIT 2:
const mapStateToProps = (state) => ({
posts: state.posts.items,
newPost: state.posts.item,
deletedPost2: state.posts.deletedPost
});
EDIT 3:
handleDeletedPost = (id) => {
this.setState({
postId: id
})
}
Edit 4:
//I added in constructor
this.state: dataPost: '',
//next I create function to load data and send to state dataPost
handleData = (e) => {
const {posts} = this.props;
const {dataPost} = this.state;
const letang = posts;
const postsData = dataPost;
if (postsData.length <= 0) {
this.setState({
dataPost: letang
})
} else {
console.log('stop')
}
}
// next i create in componentDidUpdate this code
componentDidUpdate(prevProps, prevState) {
const {posts} = this.props;
const indexPosts = posts.findIndex((post) => post.id === this.state.postId);
if(prevProps.posts !== posts){
this.handleData();
} else if (indexPosts !== -1)
{
this.informationAlert();
const log = posts.splice(indexPosts, 1);
console.log(log);
}
}
** When I added loop if (indexPosts !== -1) then my array is cut only one object :-)
API Posts: https://jsonplaceholder.typicode.com/posts/
The results are visible at this link when you press details and then the delete icon: https://scherlock90.github.io/api-post-task/
You need to use splice to delete an element from array.
In splice you need to provide startIndex and number of elements to remove in second argument. In below code find index using `findIndex method, second argument is 1 as we need to remove only 1 element.
Try this
componentDidUpdate (prevProps, prevState) {
if (prevProps.deletedPost) {
const { posts } = this.props
const letang = posts.splice(posts.findIndex( (post)=> post.id === prevProps.deletedPost.id), 1);
console.log(posts); // this should have array without deletedPost
}
}
This might help:
componentDidUpdate (prevProps, prevState) {
if (prevProps.deletedPost) {
const letang = this.props.posts;
letang.splice(deletedPost, 1);
}
}
the slice() takes the index of the object and an optional number of items to delete. since you just want to delete a single object you pass 1.
This might help, try filtering out the object you dont want in the array.
componentDidUpdate (prevProps, prevState) {
if (prevProps.deletedPost) {
const letang = this.props.items.filter(p => p.id !== prevProps.deletedPost.id);
}
}
UPDATED
I think you should be deleting the items in your redux store rather than trying to delete the posts from your api since the api might rather be generating the same data randomly. Change your actionCreator to
export const deletedPost = (id) => {
dispatch({
type: DELETED_POST,
payload: id
});
};
Then use this in your reducer so you can focus on items array coming from your reducer store. Then remove deletedPost: [] from your reducer.
...
case DELETED_POST:
const newItems = state.items.filter(p => p.id !== action.payload);
return {
...state,
items: [ ...newItems ],
};
...
use splice() to delete :), you can find the index of post which should be deleted and then delete it by using this method.
I'm using express and npm MySQL to develop an API.I have a json request in this format:
{
"payments":[
{
"PolicyNo": "ME3",
"PaymentDate": "2019-04-16T18:00:00.000Z",
},
{
"PolicyNo": "PIN001q",
"PaymentDate": "2019-04-16T18:00:00.000Z",
}]
}
I want to check the database if the policyNo exists before inserting. To avoid the common ERR_HTTP_HEADERS_SENT, I've looped through the payments querying the database with the PolicyNo. If it exists it's pushed into a success array if it doesn't it's pushed into a failed array.
This works perfectly but I can't access these arrays outside the callback.
Here's what I've tried:
router.post('/bla', (req, res)=>{
const values = []
const failedvalues = []
let sql = 'SELECT PolicyNo from pinclientinfo WHERE PolicyNo=?'
req.body.payments.forEach(element => {
connection.query(sql,element.PolicyNo,(err, rows) =>{
if(!err){
if(rows && rows.length > 0){
values.push(element.PolicyNo, element.PaymentDate)
}else{
failedvalues.push(element.PolicyNo)
}
}
})
})
res.json({
failed:failedvalues,
success:values
})
})
Here's the response I'm getting:
{
"failed": [],
"success": []
}
This has some major problems, mostly conceptually.
Firstly the forEach is synchronous will be called payments.length number of times, but the sql query is Asynchronous so it will complete in the future.
I think you are confused between synchronous and asynchronous functions and how they work.
But you can solve this (in your case) atleast two ways.
1) Use the IN syntax and get the array. Iterate over it and do stuff. "SELECT PolicyNo from pinclientinfo WHERE PolicyNo in (...)"
let sql = 'SELECT PolicyNo from pinclientinfo WHERE PolicyNo IN (' + Array(req.body.payments).fill('?').join(',') + ')'
const policies = req.body.payments.map(p => p.PolicyNo);
const values = [];
const failedvalues = [];
connection.query(sql, ...policies, (err, rows) => {
//now check each row..
rows.forEach(element => {
//Not optimized only depicts logic
///do stuff
/// like fill values and failedvalues
if(policies.indexOf(element.PolicyNo) > -1){
values.push(...)
}else{
failedvalues.push(...)
}
});
res.json({
failed: failedvalues,
success: values
})
})
Which will be 1 DB call.
2) The other approach is (not very good) doing multiple db calls and check for count.
let sql = 'SELECT PolicyNo from pinclientinfo WHERE PolicyNo=?'
let count = 0;
req.body.payments.forEach(element => {
connection.query(sql, element.PolicyNo, (err, rows) => {
if (!err) {
if (rows && rows.length > 0) {
values.push(element.PolicyNo, element.PaymentDate)
} else {
failedvalues.push(element.PolicyNo)
}
}
// check If all Complete
count+=1;
if(count === req.body.payments){
//all complete
res.json({
failed: failedvalues,
success: values
})
}
})
})
BUT SERIOUSLY, USE PROMISE. USE ASYNC/AWAIT USE THOSE SWEET LITTLE FEATURES ES6 GIVES YOU
Check out: this post
because connection.query is asynchronous, so return:
{
"failed": [],
"success": []
}
use promise and await you can synchronized resolve mysql data
use Promise.all() you can synchronized resolve list of promise
router.post("/bla", async (req, res) => {
let values = [];
let failedvalues;
let promises = [];
let sql = "SELECT PolicyNo from pinclientinfo WHERE PolicyNo=?";
req.body.payments.forEach(element => {
promises.push(
new Promise(function(resolve, reject) {
connection.query(sql, element.PolicyNo, (err, rows) => {
if (!err) {
if (rows && rows.length > 0) {
values.push(element.PolicyNo, element.PaymentDate);
} else {
failedvalues.push(element.PolicyNo);
}
}
resolve();
});
})
);
});
await Promise.all(promises);
res.json({
failed: failedvalues,
success: values
});
});
I'm trying to create an api that will return a nested json, coming from two related tables student and studentSubjects
[{
id:"1",
name: "John",
subjects: [{
id:"1",
subject: "Math"
},
{
id:"2",
subject: "English"
}
]
},
{
id:"2",
name: "Peter",
subjects: [{
id:"1",
subject: "Math"
},
{
id:"2",
subject: "English"
}
]
}]
My code looks like this:
this.get = function(res){
db.acquire(function(err, con){
con.query('SELECT * FROM students', function(err, results){
if (err){
res.send({status: 0, message: 'Database error'});
}else{
res.send({status: 1, data: results});
}
})
con.release()
})
}
I know the query should have joins, but it only returns single row. I tried also to make a loop, it won't work because its async
Thanks for your help!!
You cannot create a nested JSON from a MySQL query because it will always return a flat result.
Anyway, to create a nested JSON you should create multiple queries and insert the corresponding array object where needed.
You should really consider using Promises for creating nested queries because it will allow you to make asynchronous operations back to back.
Below code will also close the connection if an error occurs in any of the queries.
PS: I explained each step in the comments in the code below
Imagine having a database called 'School' and three tables called 'Student', 'Subject' and 'Link_student_subject'.
// Instantiate mysql datase variables
const mysql = require( 'mysql' );
const config = {
host : 'localhost',
user : 'root',
password : 'root',
database : 'school'
}
var connection;
// Instantiate express routing variables
const express = require('express');
const router = express.Router();
module.exports = router;
// Wrapper class for MySQL client
// - Constructor creates MySQL connection
// - Connection opened when query is done
// - Promise is resolved when executing
// - Promise returns reject in case of error
// - If promise resolved rows will be the result
class Database {
constructor( config ) {
this.connection = mysql.createConnection( config );
}
query( sql, args ) {
return new Promise( ( resolve, reject ) => {
this.connection.query( sql, args, ( err, rows ) => {
if ( err )
return reject( err );
resolve( rows );
} );
} );
}
close() {
return new Promise( ( resolve, reject ) => {
this.connection.end( err => {
if ( err )
return reject( err );
resolve();
} );
} );
}
}
// Function that will execute a query
// - In case of an error: ensure connection is always closed
// - In case of succes: return result and close connection afterwards
Database.execute = function( config, callback ) {
const database = new Database( config );
return callback( database ).then(
result => database.close().then( () => result ),
err => database.close().then( () => { throw err; } )
);
};
// Instantiate Database
var database = new Database(config);
// Express routing
router.get('/students', function (req, res) {
// Variables - Rows from Students & Subjects & Link_student_subject
let rows_Students, rows_Subjects, rows_Link_Student_Subject;
// Create a Promise chain by
// executing two or more asynchronous operations back to back,
// where each subsequent operation starts when the previous operation succeeds,
// with the result from the previous step
Database.execute( config,
database => database.query( "select a.*, null as subjects from student a" )
.then( rows => {
rows_Students = rows;
return database.query( "select * from subject" )
} )
.then( rows => {
rows_Subjects = rows;
return database.query( "select * from link_student_subject" )
} )
.then( rows => {
rows_Link_Student_Subject = rows;
} )
).then( () => {
// Create your nested student JSON by looping on Students
// and inserting the corresponding Subjects array
for (let i = 0; i < rows_Students.length; i++) {
let arraySubjects = [];
for (let x = 0; x < rows_Link_Student_Subject.length; x++) {
if(rows_Students[i].id == rows_Link_Student_Subject[x].id_student){
arraySubjects.push(searchObjInArray(rows_Subjects, "id", rows_Link_Student_Subject[x].id_subject));
}
}
rows_Students[i].subjects = arraySubjects;
}
res.send(JSON.stringify(rows_Students));
} ).catch( err => {
// handle the error
res.send(err);
});
});
// Function - search if object in array has a value and return that object
function searchObjInArray(array, arrayProp, searchVal){
let result = null;
let obj = array.find((o, i) => {
if (o[arrayProp] == searchVal) {
result = array[i];
return true; // stop find function
}
});
return result;
}
If you run this code with node and go to "127.0.0.1/students" it will return exactly the same JSON as in your question.
All credits and extra info on MySQL and promises - https://codeburst.io/node-js-mysql-and-promises-4c3be599909b
MySQL 5.7+ has a JSON datatype that you can leverage for your "subjects" field. Here's a great tutorial on how to use that:
https://www.sitepoint.com/use-json-data-fields-mysql-databases/