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
Related
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/
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;
}
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))
}
I'm running into some issues with casting ObjectId in express.js using mongoose.
In my route i have tried both casting before as well as just using the req.params.id directly. Nothing seems to work. I'm 100% certain the id is correct. I have tried creating a new post and directly copying the id multiple times.
Any ideas why my ObjectId is not recognized?
My Schema:
let PostSchema = new Schema({
_id: {type: mongoose.Schema.Types.ObjectId, auto: true},
title: String,
author: String,
date: { type: Date, default: Date.now()},
body: String,
comments: [CommentSchema],
upvotes: Number,
downvotes: Number,
});
My route:
app.post('/api/post/:id/comment', (req, res) => {
let comment = new PostComment({
author: req.body.author,
body: req.body.body,
date: req.body.date,
upvotes: 0,
downvotes: 0,
})
const id = mongoose.ObjectId.cast(req.params.id)
Post.findOneAndUpdate(
{_id: id},
{ $push: {comments: comment}}
)
.then(result => {
if(!result) {
res.sendStatus(404).send({
success: 'false',
message: 'Comment not added',
});
} else {
res.status(200).json(result);
}
})
.catch(err => console.log(err));
});
The Error message:
Cast to ObjectId failed for value "{ id: \'5cc3632db9e2405960e3ed0e\' }" at path "_id" for model "Post"
Extra route with same issue:
// get single post by id
app.get("/api/post/:id", (req, res) => {
const id = req.params;
Post.findById(id)
.exec()
.then(result => {
if(!result) {
res.sendStatus(404).send({
success: 'false',
message: 'No post found',
});
} else {
res.status(200).json(result);
}
})
.catch(err => console.log(err));
});
It seems as soon as you post on SO you will find the answer yourself, so here goes.
This function will effectively cast a string to an ObjectId: mongoose.Types.ObjectId(req.params.id);
I am working on a book library API where a user can borrow and update.
This is my logic for borrowing a book:
BorrowBooks(req, res) {
Book.findOne({
where: {
title: req.body.booktitle,
author: req.body.author,
}
})
.then(book => {
if (!book) {
res.status(404).send({
message: "Book not found!"
})
} else {
return Borrower
.create({
booktitle: req.body.booktitle,
borrowDate: Date.now(),
returnDate: null,
userId: req.params.userId,
})
.then(borrower => {
res.status(200).send(borrower)
book.update({
count: book.count - 1,
});
})
.catch((e) => {
return res.status(400).send(e)
})
}
});
},
To return a book I have the following:
returnBooks(req, res) {
Book.findOne({
where: {
title: req.body.title,
author: req.body.author,
}
})
.then((book) => {
if (!book) {
return res.status(400).send({
message: "There is no book like that!"
})
} else {
book.update({
count: book.count + 1,
})
Borrower.findOne({
where: {
id: req.params.userId,
booktitle: req.body.title,
}
})
.then((returnedBook) => {
returnedBook.update({
returnDate: Date.now()
})
.then(() => res.status(200).send({
message: "book successfully returned",
returnedBook
}))
})
}
})
}
This works ok (i think) for one book, but if a user borrows 2 or more books and i try to return them, it does not work.
How can it work so that it would return more instance of a borrowed book. How can it notice the new id of the new book borrowed?
If i try to return a second book, it throws the following error?
Unhandled rejection TypeError: Cannot read property 'update' of null
at Borrower.findOne.then (C:\Users\okonjiemmanuel\Desktop\hellobooks\server\controllers\book.js:142:23)
at tryCatcher (C:\Users\okonjiemmanuel\Desktop\hellobooks\node_modules\bluebird\js\release\util.js:16:23)
at Promise._settlePromiseFromHandler (C:\Users\okonjiemmanuel\Desktop\hellobooks\node_modules\bluebird\js\release\promise.
js:512:
Have you tried using .findAll?
http://docs.sequelizejs.com/class/lib/model.js~Model.html#static-method-findAll
Book.findAll({
where: {
title: req.body.title,
author: req.body.author
}
})
depending on if you want to use the instance model or raw values, you'll have to pass some options. ie: raw: true