2

I have this LikeSchema for Posts and what i want to achieve is check whether the user id exists from these array of Likes Document's _user_id

Supposed I have this array of Likes document

[
  {
    id: 'a',
    _user_id: 'u1',
    _post_id: 'p1'
  },
  {
    id: 'b',
    _user_id: 'u2',
    _post_id: 'p1'
  }
]

How do I check if user id u1 exists in likes array documents using aggregation?

I have this Like Schema

const LikeSchema = new Schema({
    _post_id: {
        type: Schema.Types.ObjectId,
        ref: 'Post',
        required: true
    },
    _user_id: {
        type: Schema.Types.ObjectId,
        ref: 'User',
        required: true
    },
})

And my aggregation

const result = await Post.aggregate([
  {
    $match: { privacy: 'public' }
  }, 
  {
    $lookup: {
      from: 'likes',
      localField: '_id',
      foreignField: '_post_id',
      as: 'likes'
    }
  },
  {
     $addFields: {
        isLiked: {
          $in: [req.user._id, '$likes'] // WONT WORK SINCE I STILL HAVE TO MAP AS ARRAY OF _user_id
        }
     }  
   }
])

The solution I have in mind is to map first the array to only have user id values then perform the $in expression. How do I map the likes array from lookup in aggregation stages so that it will only contain arrays of user id values to make the $in expression match? Or maybe there is a better way to check for value that exists in array of objects?

2 Answers 2

2

Finally found the answer. Turns out, there exists a $map operator in aggregation. This is how I used it

const result = await Post.aggregate([
  {
    $match: { privacy: 'public' }
  }, 
  {
    $lookup: {
      from: 'likes',
      localField: '_id',
      foreignField: '_post_id',
      as: 'likes'
    }
  }, 
  {
    $addFields: {
       likeIDs: { // map out array of like id's
         $map: {
           input: "$likes",
           as: "postLike",
           in: '$$postLike._id'
         }
       }
    }
  },
  {
     $addFields: {
        isLiked: {
          $in: [req.user._id, '$likeIDs'] // it works now
        }
     }  
   }
])
Sign up to request clarification or add additional context in comments.

Comments

2

It seems you can accomplish this in a cleaner way just using one addFields.

const result = await Post.aggregate([
  {
    $match: { privacy: 'public' }
  }, 
  {
    $lookup: {
      from: 'likes',
      localField: '_id',
      foreignField: '_post_id',
      as: 'likes'
    }
  }, 
  {
    $addFields: {
      isLiked: {
        $in: [req.user._id, "$likes._id"]
      }
    }
  }
])

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.