I have this relationship
User -> Cartlists <- Product
I am trying to show the products I have in my cartlists by querying it like this using the where function
router.get('/cart', ensureAuthenticated, async function (req, res) {
let cartlists = await Cartlist.findAll()
Product.findAll({
include: User,
where: { productId: cartlists.productProductId },
raw: true
})
.then((cartlists) => {
res.render('checkout/cart', { cartlists });
})
.catch(err =>
console.log(err));
})
However, when I debugged it, it shows me that cartlists.productProductId is undefined even though there is a value in mySQL. I also get an error message saying
'WHERE parameter "productId" has invalid "undefined" value'
Does anyone know why it gives me an undefined value even though there are indeed values in MySQL table and how I might be able to fix this? Or how can I query just the products I have added to my cartlists table?
Related
I have a project where I have two main tables: Contacts and Workers
I also have a join table called WorkerContacts
In my project, I give the user the option of deleting contacts, something that would also require deleting elements of the join table. My concern is that with my current setup (seen below), if I run into an error where I successfully delete a contact, but then fail to delete the associated join tables (resulting from an error), that would throw off everything. So my question is, is there a way to refactor this so that it ensures that both have been completed before doing the actual deletions then sending the promise to the front end?
Here's my current situation:
Frontend:
export const destroyContact = (contact_id) => dispatch => {
axios.post(`http://localhost:3001/contacts/destroy`, {id: contact_id})
.then(() => {
dispatch({type: 'CONTACT_DESTROYED', payload: contact_id});
axios.post(`http://localhost:3001/workerContacts/destroy`, {id: contact_id}) //I'm scared that the first thing will run but the second one won't, causing a lot of problems. We can deal with this by just throwing a big error message for the user hopefully
.then(() => {
dispatch({type: 'JOIN_TABLE_ROWS_DESTROYED', payload: contact_id});
})
.catch(err => dispatch({type: 'ERROR_CAUGHT', payload: {err_message: err.response.data.message, err_code: err.response.request.status, err_value: err.response.request.statusText}}))
})
.catch(err => dispatch({type: 'ERROR_CAUGHT', payload: {err_message: err.response.data.message, err_code: err.response.request.status, err_value: err.response.request.statusText}}))
}
I'm using redux as well so that's why I have all of the dispatch and whatnot, but essentially I've split the deletions into two axios calls: one where I delete the contact and one where I delete the join tables.
Backend:
For the contact I have this:
export const destroy = (req, res) => {
// Here is when we want to remove an existing contact
Contact.deleteMe(req.body.id)
.then(() => res.json("Contact deleted"))
.catch((err) => res.status(500).json({message: "Something went wrong when trying to save delete this. Try and reload the page and try again "}))
}
And the associated deleteMe function:
static deleteMe(customer_id){
//Uses SQL to delete an individual customer element
return db.execute('DELETE FROM contacts WHERE id = ?', [customer_id]);
}
For the jointable, I have this:
export const destroy = (req, res) => {
// Here is when we want to remove an existing contact
JoinTable.deleteMe(req.body.id)
.then(() => res.json("Join tables deleted"))
.catch(err => res.status(500).json({message: "Something went wrong on our end. Try to reload the page and start again"}))
}
And the associated deleteMe function:
static deleteMe(customer_id){
//Uses SQL to delete an individual customer element
return db.execute('DELETE FROM workercontacts WHERE workerContacts.contact_id = ?', [customer_id]);
}
I'm using a MySQL database if that helps.
Hopefully this is enough information, but if you require more, I can definitely provide you with it.
Just use a single call and execute the DELETE commands in a transaction:
export const destroyContact = (contact_id) => (dispatch) => {
axios
.post(`http://localhost:3001/contacts/destroy`, { id: contact_id })
.then(() => {
dispatch({ type: 'CONTACT_DESTROYED', payload: contact_id });
dispatch({ type: 'JOIN_TABLE_ROWS_DESTROYED', payload: contact_id });
})
.catch((err) =>
dispatch({
type: 'ERROR_CAUGHT',
payload: {
err_message: err.response.data.message,
err_code: err.response.request.status,
err_value: err.response.request.statusText,
},
})
);
};
One the backend:
static async function deleteMe(customer_id) {
await db.execute('START TRANSACTION');
try {
await db.execute('DELETE FROM contacts WHERE id = ?', [customer_id]);
await db.execute('DELETE FROM workercontacts WHERE workerContacts.contact_id = ?', [customer_id]);
await db.execute('COMMIT');
} catch (err) {
await db.execute('ROLLBACK');
}
}
...
export const destroy = (req, res) => {
// Here is when we want to remove an existing contact
Contact.deleteMe(req.body.id)
.then(() => res.json("Contact deleted"))
.catch((err) => res.status(500).json({message: "Something went wrong when trying to save delete this. Try and reload the page and try again "}))
}
I'm building Full Stack, Social media app using Sequelize ORM.
sequelize: 6.6.5
sequelize-cli: 6.2.0
My database is built of tables Users, Posts and ReadPosts - which has two foreign keys - UserId and PostId.
One of the features of the app, is that user can easily see new posts, that have not been read by him/her yet, so every time user reads a post it generates a row in ReadPost table, made of UserId (who read the post) and PostId (which was read by the user).
What I'm trying to do now, is to display all posts that have not been read, so it would be some kind of excluding left join, that would get all existing posts, and exclude those pots from ReadPost with given userId, but I can't figure out how to do it with Sequlize.
ReadPost model:
module.exports = (sequelize) => {
const readPost = sequelize.define("ReadPost", {})
readPost.associate = models => {
readPost.belongsTo(models.User, {
foreignKey: {
allowNull: false
},
onDelete: "CASCADE",
foreignKeyConstrains: true
})
readPost.belongsTo(models.Post, {
foreignKey: {
allowNull: false
},
onDelete: "CASCADE",
foreignKeyConstrains: true
})
}
return readPost
}
I know I could do it virtually and just run findAll() on posts, and not display those that have not been read yet, depending on some javascript flag or simply class, but this is a project for my portfolio so I want to do it properly. Can I have some help please?
#Anatoly
I had to play a bit with your code, as I'm using newer version of sequelize and got something like this:
exports.showAllUnreadPosts = (req, res, next) => {
db.Post.findAll({
where: {
"ReadPost.id": null,
userId: res.locals.userId //userId extracted from authorization middleware
},
include: [{
model: db.ReadPost,
required: false,
attributes: []
}]
})
with that it retuns
"error": "Error SequelizeDatabaseError: Unknown column 'Post.ReadPost.id' in 'where clause'"
I tried to understand the line '"ReadPost.id": null', but as far as I understand sql syntax it would be looking for that column in Post table? I don't have such column, relation exists in ReadPost table, where it gathers userIds and postIds, not sure if my implementation is clear
Just in summary - I need to get all existing posts from Post table and compare it with ReadPost table, where postId and userId are stored. So probably I'd have to run findAll on Posts, findAll on ReadPost with current userId, and exclude all those postIds recorded in ReadPost from Post.findAll
Have a look screenshoot of how currently data looks like in those tables:
picture of DB tables
So baisically I need Post.findAll() + ReadPost.findAll() where userId: res.locals.userId and return all posts from Post table but do not exist with that ReadPost query.
I hope that makes it more clear.
#Anatoly 11/03/22
Query works now, but returns only posts that have not been read by ANY user (row doesn't exist) and the user is the author of the post.
What I managed to do for now, is get all posts that have been read by the user (code below). I need exact opposite of it (row doesn't exist or it exists, but not with this userId)
So, from all posts that exist, Select those read by user, and exclude those else from all of the posts in the DB
exports.showAllUnreadPosts = (req, res, next) => {
db.Post.findAll({
where: {
'$readposts.UserId$': res.locals.userId // User Id extracted from auth middleware
},
include: [{
model: db.ReadPost,
required: false,
attributes: [],
}]
}).then(unreadPosts => {
res.status(200).json(unreadPosts);
})
.catch((error) => {
res.status(500).json({
error: 'Error ' + error
})
})
}
Can you please advise?
Right, it seems like I found solution with a great help from #Anatoly.
I'm not sure, if it's a good idea, since I added a second method in the THEN block, I'm happy to get any feedback on it.
exports.showAllUnreadPosts = (req, res, next) => {
db.Post.findAll({
where: {
'$readposts.UserId$': res.locals.userId // User Id extracted from auth middleware
},
attributes: ['id'],
include: [{
model: db.ReadPost,
required: false,
attributes: [],
}]
}).then(readPosts => {
db.Post.findAll({
where: {
id: {
[Op.not]: (() => readPosts.map(readPost => readPost.id))()
}
}
})
.then((unreadPosts) => {
res.status(200).json(unreadPosts);
})
.catch((error) => {
res.status(500).json({
error: 'Error' + error
})
})
})
.catch((error) => {
res.status(500).json({
error: 'Error ' + error
})
})
}
First of all, there is a method that checks all the posts that are already read by the user in readpost table and returns post ids. Secondly in the THEN block, it gets all the existing posts in the db, and excludes those with ids from above method (by [OP.not]). I hope it makes sense, not sure about performance.
You can query all posts that doesn't have a link record in ReadPost by adding a condition Readpost.id is null like this:
const unreadPosts = await Post.findAll({
where: {
'$ReadPost.id$': null,
userId: userId
},
include: [{
model: ReadPost,
required: false,
attributes: [],
where: {
UserId: userId
},
}]
})
And of course, you need to add an association from Post to ReadPost:
Post.hasMany(ReadPost, <some_options_here>);
I am having this issue where the result of the MySQL query in NodeJS keeps returning the results in the console and I am wondering why is this happenning?
Here is what I have done:
Server.js
app.get("/api/listproduct", (req, res) => {
db.query("SELECT * FROM products" , (err, result) => {
if (err) {
console.log(err);
} else {
console.log(result)
res.send(result);
}
}
)
})
ShowProduct.js
useEffect(async () => {
const result = await axios.get('http://localhost:3000/api/listproduct');
console.log(result.data)
setProducts(result.data);
});
As you can see that the result are sort of looping to the console as shown here where it was supposed to just return only one set rather than many of the same sets of results.
What am I missing here and how to solve this? Many thanks in advance and greatly appreciate any helps. Thanks
This has nothing to do with the Nodejs/MySQL backend, but your frontend React code.
You don't have a dependency array in your useEffect, so it's called every time the component is rendered. Since it calls setState, it causes a new render, and effectively an infinite loop of renders. If you don't have dependencies for your effect, add an empty array to make the effect get called only once.
useEffect(async () => {
const result = await axios.get("http://localhost:3000/api/listproduct");
setProducts(result.data);
}, []); // <- that empty array
I'm trying to validate a date field based on information stored in the database through another model.
When I test the api, validation works correctly throwing the exception, however, the insertion occurs before this exception. That is, it does not prevent the insertion in thedatabase. Where I went wrong?
This is my validate function:
module.exports = (sequelize, DataTypes) => {
const Step = sequelize.define('Step', {
...
resultDate: {
type: DataTypes.DATE,
validate: {
isEven(value){
sequelize.models.Call
.findById(this.call_id)
.then(call => {
if(value >= call.endingDate) throw new Error('Error message here!');
});
...
And this is the result:
Executing (default): SELECT [...] `Call`.`id` = '19c7e81e-5c23-4fd5-8623-0170deee6cd4');
Executing (default): INSERT INTO `Steps` [...];
Unhandled rejection Error message here!
Clearly, the initial SELECT is to perform validation, however, before the validation quit and throw the exception, the API inserts into the database and returns success already!
How do I ask the model to wait for all validations before inserting?
By changing custom validator arity (the second argument is a callback) you can change it to an asynchronous handler. So your code should look like this:
module.exports = (sequelize, DataTypes) => {
const Step = sequelize.define('Step', {
...
resultDate: {
type: DataTypes.DATE,
validate: {
isEven(value, next){
sequelize.models.Call
.findById(this.call_id)
.then(call => {
next(value >= call.endingDate ? 'Error message here!' : null)
})
.catch(next);
...
I am using Knex with node.js to create a table and insert some data to it. First I was first creating table and then inserting data but it ended up so that sometimes table was not created yet when data was going to be inserted. Then I ended up using callbacks like below. Now I'm mixing callbacks and promises and I'm not sure if it's very good thing. What could I do to make following work without callback and still take care that table is created before inserting data?
function executeCallback(next, tableName) {
knex.schema.hasTable(tableName)
.then((exists) => {
if (!exists) {
debug('not exists');
// Table creation for mysql
knex.raw(`CREATE TABLE ${tableName} ( id INT(6) UNSIGNED AUTO_INCREMENT PRIMARY KEY, timestamp BIGINT NOT NULL, deviceId VARCHAR(255) NOT NULL, data JSON )`)
.then((rows) => {
debug(rows);
next('Table created (mysql)');
})
.catch((err) => {
debug(`Error: ${err}`);
next(`Error: ${err}`);
});
} else {
debug('Table exists');
next('Table exists');
}
});
}
.
executeCallback((response) => {
debug('back from callback', response);
debug('insert');
knex(req.body.tableName).insert({
timestamp: req.body.timestamp,
deviceId: req.body.deviceId,
data: req.body.data,
})
.catch((err) => {
debug(`Error: ${err}`);
res.status(500).json({ success: false, message: `Error: ${err}` });
})
.then((dataid) => {
debug(`Inserted with id: ${dataid}`);
res.status(201).json({ success: true });
});
}, req.body.tableName);
In general mixing callbacks and Promises is discouraged. I would suggest looking into the async/await pattern for using Promises, as that is often easier to read in code. It works well with knex js too.
One trick with Node callbacks is the convention of the function parameters, where the first parameter is the error, and the second is the success result. Like this: function (error, results) {...} This makes the result easy to check, like
if(error) {
// do error stuff
return
}
// do success stuff with `results`
One could call that function like next(new Error('bad')) for an error, or next(null, 'success object') for a success.
Your callback next is only taking one parameter, and you are not checking its value. It matters whether the result was 'Table Exists' 'Table Created' or 'Error' to what you do next.
You might try something like this:
async function handleInsert(tableName, res) {
try {
let hasTable = await knex.schema.hasTable(tableName)
if(!exists) {
let createResult = await knex.raw(`CREATE TABLE...`)
// check create results, throw if something went wrong
}
//table guaranteed to exist at this point
let insertResult = await knex(req.body.tableName).insert({
timestamp: req.body.timestamp,
deviceId: req.body.deviceId,
data: req.body.data,
})
debug(`Inserted with id: ${insertResult}`) //might need insertResult[0]
res.status(201).json({ success: true })
} catch(err) {
// any error thrown comes here
console.log('Server error: ' + err)
res.error('Bad thing happened, but do not tell client about your DB')
}
}
One more thing. In general, you can either assume the tables you need exist already. Or use a migration to build your DB on server start/update.