How to get data with just inserted data with Sequelize in PostgreSql? - javascript

I want to get updated table values after I add user to my "WOD" table. For instance, I have 2 users in my WOD table and after I add third user , I want to return a response to client with I have just inserted data (third guy). But now , I can only return first 2 users because I can not take updated values. Of course I can make another query to get updated table values after I insert, but is there any better solution ? Here is my codes;
const addUser = async (req, res) => {
try {
const { userId, wodId } = req.body;
if (!userId || !wodId) {
res.status(400).send({ status: false, message: 'need userId and wodId' });
}
const wod = await Wod.findByPk(wodId, {
include: [
{
model: User,
as: 'Participants',
through: { attributes: [] }
}
]
});
//check capacity if full.
if (wod.Participants.length >= wod.capacity) {
res
.status(403)
.send({ status: false, message: 'Capacity of this class is full!' });
}
const result = await wod.addParticipants(userId);
res.status(201).json({ status: !!result, wod });
} catch (error) {
res.status(500).send({ status: result, message: error.message });
console.log(error.message);
}
};

As a result of many-to-many association sequelize.sync will generate some functions for us. You are used addParticipants function and this returns an array that added to the assocation(userwod) table.
In this array you will find some id fields(join table fields) because you just run like this INSERT INTO 'user_wods' ('user_id''wod_id') VALUES (2,1). If you want to return the added user's information then you should run a SELECT * FROM 'user' WHERE 'id'=2.
You must call reload function for fetch the third guy.
await wod.reload()

Related

JS file not pulling model.findByPk() using "/:id"?

I'm trying to pull items from my database using each item's id, but am receiving an empty object when running it through Insomnia. For example, in the code below, I would like to pull a category by ID, but also include any associated Products.
Any idea what I might be doing wrong? Thank you in advance!
router.get('/:id', async (req, res) => {
try {
const oneCategory = await Category.findByPk({
include: [{ model: Product }]
});
// console.log(oneCategory);
if (!oneCategory) {
res.status(404).json({ message: 'No category found with that id!' });
return;
}
res.status(200).json(oneCategory);
} catch (error) {
res.status(500).json(error);
}
});
When calling the findByPk method, you need to pass the key you are looking for. In this particular case, the code should look like this:
router.get('/:id', async (req, res) => {
try {
const oneCategory = await Category.findByPk(req.params.id, {
include: [{ model: Product }]
});
if (!oneCategory) {
res.status(404).json({ message: 'No category found with that id!' });
return;
}
res.status(200).json(oneCategory);
} catch (error) {
res.status(500).json(error);
}
});
So just grab the id from the URL with req.params.id and pass it to findByPk. However, it could be a good idea to check so that the id is in fact an integer before doing so :)

Sharing user_id value between two MySql table

I'm working on my middleware AuthController.js below. The middleware is part of a CRUD app. I created exports.create which when requested will collect the first name and last name from the CRUD form. Once collected the MySql INSERT query, will insert the data on the MySql user table which is working fine.
What I cannot achieve and I need help is that together with the first name and last name info I want to insert also the variable { user_id: decoded.id }, decoded.id is a variable which take the user_id value from another MySql table called login.
When I request export.create the following error shows on the terminal:
(node:18780) UnhandledPromiseRejectionWarning: TypeError: argument callback must be a function when provided
Basically I want that the value under user_id column from the login table is transferred to the user_id column on user table. Thank for any help.
exports.create = async (req, res, next) => {
if (req.cookies.jwt) {
try {
//1)verify the token
var decoded = await promisify(jwt.verify)(req.cookies.jwt,
process.env.JWT_SECRET
);
// console.log(decoded);
const { first_name, last_name } = req.body;
connection.query('INSERT INTO user SET first_name = ?,last_name = ?', { user_id: decoded.id }, [first_name, last_name,], (err, rows) => {
if (!err) {
res.render('add-crew', { alert: 'Crew member added succesfully!' });
} else {
console.log(err);
}
console.log('The data from user table:\n', rows);
});
} catch (error) {
console.log(error);
return next();
}
}
};
The connection.query function takes in two to three arguments: the SQL statement, (the values) and the callback. Here, the function is taking four arguments, so it thinks [first_name, last_name,] is the callback.
What you can do is:
...
connection.query('INSERT INTO user SET user_id = ?, first_name = ?,last_name = ?', [decoded.id, first_name, last_name,], (err, rows) => {
if (!err) {
res.render('add-crew', { alert: 'Crew member added succesfully!' });
} else {
console.log(err);
}
console.log('The data from user table:\n', rows);
});
...
I hope this is what you are looking for.
Edit you could also do:
...
connection.query('INSERT INTO user SET ?', {user_id: decoded.id, first_name: first_name, last_name: last_name}, (err, rows) => {
if (!err) {
res.render('add-crew', { alert: 'Crew member added succesfully!' });
} else {
console.log(err);
}
console.log('The data from user table:\n', rows);
});
...

Mongoose - How to Chain Save So Data Can Be Saved to Multiple Collections

I have read all sorts of variations of this on stackoverflow but I cannot seem to find a post that exactly explains what I'm trying to achieve, at the same time I believe this has to be a very common task during saving data.
So I need to save data to one collection and then read the _id from that doc and save it to a doc in a different collection. I have the following code and I can see the correct data with console.log but I don't see the data being saved to the database.
Appreciate if someone can guide me in the right direction.
Thank you!
router.post('/signup', async (req, res) => {
const { email, password, name, country } = req.body;
try {
const user = new User({ email, password });
await user.save((error, doc) => {
if (error) {
console.log(error);
} else {
const userProfile = new UserProfile({ userId: doc._id, name, country });
userProfile.save((error, doc) => {
if (error) {
console.log(error)
} else {
console.log(doc) // Can see this log with the correct data
}
});
}
});
const token = jwt.sign({userId: user._id}, 'MY_KEY');
res.send({ token });
} catch(error) {
return res.status(422).send(error.message)
}
})

Elegant way to update many properties with mongoose

I have a model with 7 properties and want to update them all when there is an edit request from front-end. Is there any elegant way to do so, or do I have to type all of them manually like in my code bellow (whitch by the way works fine for me, but looks really ugly).
exports.saveDish = (req, res, next) => {
const {
name,
description,
price,
category,
vegetarian,
hot,
menuPosition,
} = req.body;
Dish.findById(req.body._id)
.then(oldDish => {
if (oldDish) {
oldDish.name = name;
oldDish.description = description;
oldDish.price = price;
oldDish.category = category;
oldDish.vegetarian = vegetarian;
oldDish.hot = hot;
oldDish.menuPosition = menuPosition;
oldDish.save();
return res.status(204).json({ message: 'Dish data properly updated' });
}
const newDish = new Dish(req.body);
newDish.save();
return res.status(201).json({ message: 'New dish properly saved' });
})
.catch(err => console.log(err));
};
This will update an existing record and return the updated value. If no matching record is found, it will return a falsey value to the callback or promise (can't remember if it's null or something else).
Dish.findByIdAndUpdate(req.body._id, updates, {new: true}, cb)
You can try something like this :
exports.saveDish = (req, res, next) => {
/**
*
* upsert: true --> helps to insert new document if no matching doc exists
* new: true --> returns new document in output
* rawResult: true --> helps to find out whether update or insert operation is done
*
* Dish is a mongoose schema where findByIdAndUpdate is only from mongoose,
* which internally converts a string from it's first parameter into {_id : ObjectId('req.body._id')}, also uses $set operation on req.body
*
* Print data to check what's being returned, you might see entire document(data.value) being returned with some other information
*
* */
Dish.findByIdAndUpdate(req.body._id, req.body, { upsert: true, new: true, rawResult: true }, (err, data) => {
if (err) { console.log(err); res.status(200).json({ message: 'Operation Failed' }) }
if (data.lastErrorObject.updatedExisting) return res.status(204).json({ message: 'Dish data properly updated' });
return res.status(201).json({ message: 'New dish properly saved' });
})
};
Here you're updating existing document (adding new fields or updating the existing fields w.r.t. what's there is req.body) or inserting an entire new document if no matching _id is found in database, this way you avoid multiple DB calls. Here I've made it in callbacks, but earlier I've actually done it in async await, it does work either way, this should work for all of your cases listed above !!
Ref : Mongoose findByIdAndUpdate
#EddieDean, your way worked almost fine, it turns out that you have to pass any id to findByIdAndUpdate() method, so I edited it a little bit to work with unique, new dishes too.
Working code just in case:
exports.saveDish = (req, res, next) => {
if (req.body._id) {
Dish.findByIdAndUpdate(
{ _id: req.body._id },
{ ...req.body },
{ useFindAndModify: false }
)
.then(oldDish => {
if (oldDish) {
oldDish.save();
return res
.status(204)
.json({ message: 'Dish data properly updated' });
}
})
.catch(err => console.log(err));
} else {
const newDish = new Dish(req.body);
newDish
.save()
.then(result => {
return res.status(201).json({ message: 'New dish properly saved' });
})
.catch(err => console.log(err));
}
};

Mongoose - Create document if not exists, otherwise, update- return document in either case

I'm looking for a way to refactor part of my code to be shorter and simpler, but I don't know Mongoose very well and I'm not sure how to proceed.
I am trying to check a collection for the existence of a document and, if it doesn't exist, create it. If it does exist, I need to update it. In either case I need to access the document's contents afterward.
What I've managed to do so far is query the collection for a specific document and, if it's not found, create a new document. If it is found, I update it (currently using dates as dummy data for this). From there I can access either the found document from my initial find operation or the newly saved document and this works, but there must be a better way to accomplish what I'm after.
Here's my working code, sans distracting extras.
var query = Model.find({
/* query */
}).lean().limit(1);
// Find the document
query.exec(function(error, result) {
if (error) { throw error; }
// If the document doesn't exist
if (!result.length) {
// Create a new one
var model = new Model(); //use the defaults in the schema
model.save(function(error) {
if (error) { throw error; }
// do something with the document here
});
}
// If the document does exist
else {
// Update it
var query = { /* query */ },
update = {},
options = {};
Model.update(query, update, options, function(error) {
if (error) { throw error; }
// do the same something with the document here
// in this case, using result[0] from the topmost query
});
}
});
I've looked into findOneAndUpdate and other related methods but I'm not sure if they fit my use case or if I understand how to use them correctly. Can anyone point me in the right direction?
(Probably) Related questions:
How to check if that data already exist in the database during update (Mongoose And Express)
Mongoose.js: how to implement create or update?
NodeJS + Mongo: Insert if not exists, otherwise - update
Return updated collection with Mongoose
Edit
I didn't come across the question pointed out to me in my searching, but after reviewing the answers there I've come up with this. It's certainly prettier, in my opinion, and it works, so unless I'm doing something horribly wrong I think my question can probably be closed.
I would appreciate any additional input on my solution.
// Setup stuff
var query = { /* query */ },
update = { expire: new Date() },
options = { upsert: true };
// Find the document
Model.findOneAndUpdate(query, update, options, function(error, result) {
if (!error) {
// If the document doesn't exist
if (!result) {
// Create it
result = new Model();
}
// Save the document
result.save(function(error) {
if (!error) {
// Do something with the document
} else {
throw error;
}
});
}
});
You are looking for the new option parameter. The new option returns the newly created document(if a new document is created). Use it like this:
var query = {},
update = { expire: new Date() },
options = { upsert: true, new: true, setDefaultsOnInsert: true };
// Find the document
Model.findOneAndUpdate(query, update, options, function(error, result) {
if (error) return;
// do something with the document
});
Since upsert creates a document if not finds a document, you don't need to create another one manually.
Since you wish to refactor parts of your code to be shorter and simpler,
Use async / await
Use .findOneAndUpdate() as suggested in this answer
let query = { /* query */ };
let update = {expire: new Date()};
let options = {upsert: true, new: true, setDefaultsOnInsert: true};
let model = await Model.findOneAndUpdate(query, update, options);
///This is simple example explaining findByIDAndUpdate from my code added with try catch block to catch errors
try{
const options = {
upsert: true,
new: true,
setDefaultsOnInsert: true
};
const query = {
$set: {
description: req.body.description,
title: req.body.title
}
};
const survey = await Survey.findByIdAndUpdate(
req.params.id,
query,
options
).populate("questions");
}catch(e){
console.log(e)
}
Here is an example I am using. I have to return custom responses for UI updates etc. This can be even shorter. User is
const UserScheme = mongoose.Schema({
_id: String,
name: String,
city: String,
address: String,
},{timestamps: true});
const User = mongoose.model('Users', UserScheme);
async function userUpdateAdd(data){
var resp = '{"status": "error"}';
if(data){
var resp = await User.updateOne({ _id: data._id }, data).then(function(err, res){
console.log("database.userUpdateAdd -> Update data saved in database!");
if(err){
var errMessage = err.matchedCount == 0 ? "User Record does not exist, will create new..." : "Record not updated";
// If no match, create new
if(err.matchedCount == 0){
const create_user = new User(data);
resp = create_user.save().then(function(){
console.log("database.userUpdateAdd -> Data saved to database!");
return '{"status":"success", "message": "New User added successfully"}';
});
return resp;
}
// Exists, return success update message
if(err.matchedCount == 1){
return '{"status": "success", "message" : "Update saved successfully"}';
} else {
return '{"status": "error", "code": "' + err.modifiedCount + '", "message": "' + errMessage + '"}';
}
}
})
.catch((error) => {
//When there are errors We handle them here
console.log("database.userUpdateAdd -> Error, data not saved! Server error");
return '{"status": "error", "code": "400", "message": "Server error!"}';
});
}
return resp;
}
Here's an example:
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/rsvp', {useNewUrlParser: true, useUnifiedTopology: true});
const db = mongoose.connection;
db.on('error', () => {
console.log('mongoose connection error');
});
db.once('open', () => {
console.log('mongoose connected successfully');
});
const rsvpSchema = mongoose.Schema({
firstName: String,
lastName: String,
email: String,
guests: Number
});
const Rsvp = mongoose.model('Rsvp', rsvpSchema);
// This is the part you will need... In this example, if first and last name match, update email and guest number. Otherwise, create a new document. The key is to learn to put "upsert" as the "options" for the argument.
const findRsvpAndUpdate = (result, callback) => {
Rsvp.findOneAndUpdate({firstName: result.firstName, lastName: result.lastName}, result, { upsert: true }, (err, results) => {
if (err) {
callback(err);
} else {
callback(null, results);
}
})
};
// From your server index.js file, call this...
app.post('/rsvps', (req, res) => {
findRsvpAndUpdate(req.body, (error, result) => {
if (error) {
res.status(500).send(error);
} else {
res.status(200).send(result);
}
})
});

Categories

Resources