Scope of Project: I am making a newsfeed, like Facebook. And I have a like button feature that will add a like to a post item when clicked.
Problem Lets say I have two posts, post A and post B.
If I like post A and like again then my server returns "User already liked post", okay that works.
However, if I like post B then the server returns the same "User already liked post"
Query:
Feed.findOne({
owner: req.body.authorId,
$and: [
{
"posts.likes.likeList": {
$elemMatch: { user: req.user._id }
}
},
{ posts: { $elemMatch: { _id: req.body.postId } } }
]
}).then(checkedFeed => {
if (checkedFeed) {
return res.status(400).json({ Error: "User has already liked post" });
}
What I think the problem is When the user likes post B while post A is liked, the $and operator matches the req.user._id with the posts.likes.likeList of post A in the first index of the $and array. Then, it matches the _id of posts in the second index of the $and array. And then returns the entire feed as a match.
So, if I am correct in this regards, how do I write a query that matches the post id (the second index of the $and array) with the post.likes.likeList list of users?
Schema
{
owner: {
type: Schema.Types.ObjectId,
ref: "userType"
},
posts: [
{
likes: {
totalLikes: { type: Number, default: 0 },
likeList: [
{
user: { type: Schema.Types.ObjectId, ref: "User" },
avatar: { type: String },
name: { type: String },
date: {
type: Date,
default: Date.now
}
}
]
}
});
Test Data*
{
//POST B <-------
"_id" : ObjectId("5d0a61bc5b835b2428289c1b"),
"owner" : ObjectId("5c9bf6eb1da18b038ca660b8"),
"posts" : [
{
"likes" : {
"totalLikes" : 0,
"likeList" : []
},
"_id" : ObjectId("5d0a61bc5b835b2428289c1c"),
"postBody" : "Test text only",
"author" : {
"userType" : "User",
"user" : ObjectId("5c9bf6eb1da18b038ca660b8"),
"name" : "Amari DeFrance",
"avatar" : "https://stemuli.blob.core.windows.net/stemuli/profile-picture-e1367a7a-41c2-4ab4-9cb5-621d2008260f.jpg"
}
},
{
//Post A <------
"likes" : {
"totalLikes" : 1,
"likeList" : [
{
"_id" : ObjectId("5d0a66efbac13b4ff8b3b1c8"),
"user" : ObjectId("5c9bf6eb1da18b038ca660b8"),
"avatar" : "https://stemuli.blob.core.windows.net/stemuli/profile-picture-e1367a7a-41c2-4ab4-9cb5-621d2008260f.jpg",
"name" : "Amari DeFrance",
"date" : ISODate("2019-06-19T16:46:39.177Z")
}
]
},
"postBody" : "Test photo",
"author" : {
"userType" : "User",
"user" : ObjectId("5c9bf6eb1da18b038ca660b8"),
"name" : "Amari DeFrance",
"avatar" : "https://stemuli.blob.core.windows.net/stemuli/profile-picture-e1367a7a-41c2-4ab4-9cb5-621d2008260f.jpg"
},
"date" : ISODate("2019-06-19T16:25:26.123Z")
}
],
"__v" : 3
}
New Query per suggested answer
Feed.aggregate([
{
$match: {
$expr: {
$and: [
{
$eq: ["$owner", req.body.authorId]
},
{
$anyElementTrue: {
$map: {
input: "$posts",
in: {
$and: [
{
$eq: ["$$this._id", req.body.postId]
},
{
$anyElementTrue: {
$map: {
input: "$$this.likes.likeList",
as: "like",
in: {
$eq: ["$$like.user", req.user._id]
}
}
}
}
]
}
}
}
}
]
}
}
}
]).then(checkedFeed => {
if (checkedFeed.length !== 0) {
return res.status(400).json({ Error: "User has already liked post" });
}
MongoDB query test with post B having liked post from the user