Reputation: 328
I have a like button and I wish that when a user clicks on like the like in the database:
Increment if the user didn't yet like it (like with +1 and add user id from the likedBy array)
Decrease if the user already liked it (like - 1 and remove the used id from the likedBy array)
the controller :
exports.likeIdea = (req,res,next) => {
const userId = getUserId(req)
Ideas.updateOne({ _id: req.params.id}, {
$set: {
like: {
$cond: [ {$in: [userId, "$likedBy"]}, { $inc: { like: +1 } } , { $inc: { like: -1 } } ]
},
likedBy: {
$cond: [ {$in: [userId, "$likedBy"]}, { $pull: { likedBy: userId } } , { $push: { likedBy: userId } } ]
},
_id: req.params.id
}
})
.then(() => res.status(200).json({ message: 'Success'}))
.catch(error => {
res.status(400).json({ error })
});
};
the schema
const ideaSchema = mongoose.Schema({
name: { type: String, required: true},
sumup: { type: String, required: true },
description: { type: String, required: true},
published: {type: Boolean, required: true},
like: {type: Number, required: true},
likedBy: {type: [String]},
author: {type: String, required: true},
dislike: {type: Number, required: true},
dislikedBy: {type: [String]},
imgUrl: {type: String, required: true}
});
CastError: Cast to Number failed for value "{ '$cond': [ { '$in': [Array] }, { '$inc': [Object] }, { '$inc': [Object] } ] }" at path "like" [...] {messageFormat: undefined, stringValue: '"{
'$cond': [ { '$in': [Array] }, { '$inc': [Object] }, { '$inc': [Object] } ] }"', kind: 'Number', value: {…}, path: 'like', …}
Upvotes: 1
Views: 312
Reputation: 36134
The regular update query can not allow to use internal fields and aggregation operators like $cond
, so you can't do this operation with regular update query,
You can try with update with aggregation pipeline starting from MongoDB 4.2,
$inc
you can use $add
operator in aggregation update$pull
you can use $filter
to remove specific user$push
you can use $concatArrays
operatorexports.likeIdea = (req,res,next) => {
const userId = getUserId(req)
Ideas.updateOne({ _id: req.params.id},
[{
$set: {
like: {
$cond: [
{ $in: [userId, "$likedBy"] },
{ $add: ["$like", 1] },
{ $add: ["$like", -1] }
]
},
likedBy: {
$cond: [
{ $in: [userId, "$likedBy"] },
{
$filter: {
input: "$likedBy",
cond: { $ne: ["$$this", userId] }
}
},
{ $concatArrays: ["$likedBy", [userId]] }
]
}
}
}]
).then(() => res.status(200).json({ message: 'Success'}))
.catch(error => {
res.status(400).json({ error })
});
};
Upvotes: 1