Cancel Promise.all update MongoDB when one reject - javascript

I have two Model: User and Project.
User: name, projects [ { id, role } ]
Project: name, members []
I wrote a function to add a member (from User) to Project. My code:
const addMember = async (req, res, next) => {
const { userId, role, projectId } = req.body
Promise.all([
Project.findByIdAndUpdate(projectId, { $push: {members: userId}}),
User.findByIdAndUpdate(userId, { $push: {projects: { id: userId, role: role}} })
]).then(values => {
if (!values[0] || !values[1]) return next("Can not find")
return res.json({
result: 'ok',
message: "Add member successfully!",
})
}).catch(error => next(error))
}
But it does not work as I expected. If projectId wrong, nested method 1 in Promise not working but nested method 2 still working, the database will be updated. The same as userId wrong.
How can I return error when once wrong?

If I am not wrong, you want to only update user when project update is successful, for that Promise.all is not the solution, chain the promises, like
Project.findByIdAndUpdate(projectId, { $push: {members: userId}})
.then(()=>{
return User.findByIdAndUpdate(userId, { $push: {projects: { id: userId, role: role}} });
})
.then(values => {
if (!values[0] || !values[1]) return next("Can not find")
return res.json({
result: 'ok',
message: "Add member successfully!",
})
}).catch(error => next(error))

Rather than calling findByIdAndUpdate functions in the
Promise.all block. You can split the code in to two parts.
1) Define findById function which only check if the record exists and an update function to update the entries
2) execute the findById and update codes in the Promise.all separately.
const addMember = async (req, res, next) => {
const { userId, role, projectId } = req.body
Promise.all([
Project.findById(projectId, { $push: {members: userId}}),
User.findById(userId, { $push: {projects: { id: userId, role: role}} })
]).then(values => {
if (!values[0] || !values[1]) return next("Can not find")
Promise.all([
Project.update(projectId, { $push: {members: userId}}),
User.update(userId, { $push: {projects: { id: userId, role: role}} })
]).then(values => {
return res.json({
result: 'ok',
message: "Add member successfully!",
})
})
}).catch(error => next(error))
}

Related

MongoDB/Mongoose $pull an Object in an Array where _id of the Object is matching

I have this Schema here
Consider the likedTours which is an Array of Objects (Tours) (ignore position 0).
I want to pull any Objects where the _id of a Tour matches the critiria.
Adding a new Tour upon liking a tour is okay, but on unlike I don't know how to pull that item out.
Here is my function in the Controller in the Node.JS backend
const unlikeTour = async (req, res) => {
try {
TourDB.Tour.findOneAndUpdate(
{ _id: req.params.tourid },
{
$pull: { likedUsers: req.userID },
$inc: { likes: -1 },
}
).exec(async (err, docs) => {
if (!err) {
try {
await UserDB.User.findOneAndUpdate(
{ _id: req.userID },
{ $pull: { 'likedTours._id': docs._id } } //Here I need help
).exec()
return res.status(200).send({ successMessage: 'Tour successfully unliked' })
} catch (err) {
return res.status(500).send({ errorMessage: 'User not found' })
}
} else {
return res.status(500).send({ errorMessage: 'Tour not found' })
}
})
} catch (err) {
return res.status(500).send({ errorMessage: err })
}
}
This method looks for a tour and update it by pulling out the userID and decrement the likes count by -1.
And then I try to find in the UserDB that tour in the likedTours and tried to pull but it doesn't not work like that.
Thanks in advance
you can update as
await UserDB.User.findOneAndUpdate(
{ _id: req.userID },
{ $pull: { likedTours: { _id: docs._id } } } //Here I need help
).exec();
reference: https://docs.mongodb.com/manual/reference/operator/update/pull/

How can i combine two update requests into one?

I now have a code that works.
await Users.update({ selected: false }, { where: { userId: req.body.userId } });
await Users.update(
{
selected: req.body.selected,
descr: req.body.note
},
{
where:
{
entId: req.body.id,
userId: req.body.userId
}
}
);
But what if it is possible to combine these two queries into one? I need the 'selected' and 'note' field that I pass to change conditionally in the table. And all other 'selected' fields inherent to the user in the table became false.
Unfortunately, I did not find anything like that in the documentation. Thank you in advance for your help!
Unfortunately there is no such method like bulkUpdate in Sequelize so you need to call update twice and better to use a transaction to make these two queries as a one atomic operation.
await Sequelize.transaction(async transaction => {
await Users.update({ selected: false }, { where: { userId: req.body.userId }, transaction });
await Users.update(
{
selected: req.body.selected,
descr: req.body.note
},
{
where:
{
entId: req.body.id,
userId: req.body.userId
},
transaction
}
);
});
You can use the sequelize transaction and wrap it up inside try/catch,
// define transaction outside the try/catch so you can rollback if needed
const transaction = await sequelize.transaction();
try {
await Users.update({ selected: false }, { where: { userId: req.body.userId }, transaction })
.then((r) => r)
.catch((e) => {
throw e;
});
await Users.update(
{
selected: req.body.selected,
descr: req.body.note
},
{
where: {
entId: req.body.id,
userId: req.body.userId
},
transaction
}
)
.then((r) => r)
.catch((e) => {
throw e;
});
// always call commit at the end
await transaction.commit();
return true;
} catch (error) {
// always rollback
await transaction.rollback();
console.log(error);
throw error;
}

how to reproduce this code using MongoDB $push & $inc operators?

I try to make this code work but using $inc to increment number of likes & $push to push the userId to the array usersLiked:
Sauce.updateOne(
{ _id: req.params.id },
{
...sauceObject,
likes: req.body.like,
dislikes: req.body.like,
usersLiked: req.body.userId,
usersDisliked: req.body.userId,
}
)
.then(() => res.status(200).json({ message: "Sauce liked !" }))
.catch((error) => res.status(400).json({ error }));
I tried this, but it returns an error:
db.Sauce.update(
{ _id: req.params.id },
{
$push: { usersLiked: req.body.userId },
$inc: { likes: 1 },
}
.then(() => res.status(200).json({ message: "Sauce liked !" }))
.catch((error) => res.status(400).json({ error }))
);
Your help is appreciated :D
Add function to your code because unless and until you don't call function it won't work and also use async function to increment number of likes

Part of the API is not working in NodeJS. How do I fix it?

I'm trying to build a REST API in NodeJS for an online-store. My code for the POST-request looks like this:
router.post('/', (req, res, next) => {
const order = new Order({
_id: new mongoose.Types.ObjectId(),
customer_name: req.body.order.customer_name,
total_price: req.body.order.total_price,
products: req.body.order.products,
});
order
.save()
.then(result => {
req.body.order.products.forEach(value => {
let availiableQuantity = value.available_quantity - value.ordered_quantity;
Product.findOneAndUpdate({ id: value.id }, { available_quantity: availiableQuantity
})
})
res.status(201).json({
message: "Successfully created product",
createdProduct: {
customer_name: result.customer_name,
products: result.products,
}
});
})
.catch(err => {
console.log(err);
res.status(500).json({
error: err
});
});
});
The issue that I'm having is that the code in .then block is not working when I'm trying to send this POST-request, even if I try to console.log something, it doesn't do anything, everything works except the code in .then block:
.then(result => {
console.log('test')
req.body.order.products.forEach(value => {
let availiableQuantity = value.available_quantity - value.ordered_quantity;
Product.findOneAndUpdate({ id: value.id }, { available_quantity: availiableQuantity
})
})
Am I missing something out?
You can instead use async await instead of processing the next step with the then block.
router.post('/',async (req, res) => {
try{
const order = new Order({
_id: new mongoose.Types.ObjectId(),
customer_name: req.body.order.customer_name,
total_price: req.body.order.total_price,
products: req.body.order.products,
});
var result = await order.save();
req.body.order.products.forEach(value => {
let availiableQuantity = value.available_quantity -
value.ordered_quantity;
Product.findOneAndUpdate({ id: value.id }, {
available_quantity: availiableQuantity
})
res.status(201).json({
message: "Successfully created product",
createdProduct: {
customer_name: result.customer_name,
products: result.products,
}
});
} catch(e) {
res.status(500).json({
message: "Bad request",
error: e
});
}
})

mongoose findByIdAndUpdate update objects and push other onto existing field

Hello I would like to update a document in my db using findByIdAndUpdate only doing minimal calls, but some values have to be pushed onto an array and other updated.
i'm sure there must be an easy way to make this into one route instead of using the two
router.put('/notes/:id', (req, res) => {
Player.findByIdAndUpdate({
_id: req.params.id
}, {
$push: {
notes: req.body.notes
}
}, {
new: true
})
.then(player => res.status(200).json(player))
.catch(err => res.status(400).json({
'err': 'updating went wrong'
}))
})
router.put('/:id', (req, res) => {
let updates = {};
if (req.body.first) {
updates.first = req.body.first;
}
if (req.body.last) {
updates.last = req.body.last;
}
if (req.body.school) {
updates.school = req.body.school;
}
if (req.body.rank) {
updates.rank = req.body.rank;
}
Player.findByIdAndUpdate({
_id: req.params.id
}, updates, {
new: true
})
.then(player => res.status(200).json(player))
.catch(err => res.status(400).json({
'err': 'updating went wrong'
}))
})

Categories