1

I have photos_comments collection:

{
    "_id" : ObjectId(""),
    "photo_id" : ObjectId(""),
    "content" : "Comment 1",
    "is_approved" : "1",
    "user" : {
        "user_id" : ObjectId(""),
        "name" : "",
        "avatar" : ".jpg"
    },
    "likes" : [ 
        {
            "user_id" : ObjectId("")
        }
    ],
    "like_count" : 1,
    "reply_count" : 5,
    "replies" : [ 
        {
            "reply_id" : ObjectId(""),
            "content" : "Reply 1",
            "is_approved" : "1",
            "user" : {
                "user_id" : ObjectId(""),
                "name" : "",
                "avatar" : ".jpg"
            },
            "likes" : [ 
                {
                    "user_id" : ObjectId("")
                }
            ],
            "like_count" : 1
        }, 
    ]
}

I use $in to check if current user like reply comment:

$collection->aggregate(
                        [
                            [
                                '$match' => [
                                    '_id' => new ObjectId($comment_id)
                                ]
                            ],

                            [
                                '$project' => [
                                    'replies.reply_id' => 1,
                                    'replies.like_count' => 1,
                                    'replies.content' => 1,
                                    'replies.is_liked' => ['$in' => [['user_id' => $user_id], '$replies.likes']],
                                    'replies.user' => 1,
                                    'replies.created_at' => 1
                                ]
                            ],

                            ['$sort' => ["replies.reply_id" => 1]],
                            ['$limit' => 5]
                        ]);

But replies.is_liked alway return false, although it exist user_id in likes array from replies array embed.

How to fix it? Thanks!

It looks like your post is mostly code; please add some more details.

2
  • 1
    What are you actually expecting as a result? Show your expected result. Note that replies in your document as shown is an array, and therefore simple "dot notation" in a $project stage is not enough in order to alter every array element. If you expect all array elements to be altered then you must use $map Commented Sep 21, 2019 at 11:01
  • @NeilLunn I want return list replies with replies.is_liked = true if current user_id exists in likes array of replies array embed. Commented Sep 21, 2019 at 11:07

1 Answer 1

3

If you want to alter the array content to add a new field based on a condition, then you want the $map operator, and probably using $addFields if you don't want to restrict or change the rest of the document returned:

$collection->aggregate([
  [ '$match' => [
    '_id' => new ObjectId($comment_id)
  ]],
  [ '$addFields' => [
    'replies' => [
      '$map' => [
        'input' => '$replies',
        'in' => [
          'reply_id' => '$$this.reply_id',
          'content' => '$$this.content',
          'is_approved' => '$$this.is_approved',
          'is_liked' => [ '$in' => [ $user_id, '$$this.likes.user_id' ] ],
          'like_count' => '$$this.like_count'
        ]
      ]
    ]
  ]],
  ... # any other pipeline
])

Or using $mergeObjects if your MongoDB supports it and you prefer:

$collection->aggregate([
  [ '$match' => [
    '_id' => new ObjectId($comment_id)
  ]],
  [ '$addFields' => [
    'replies' => [
      '$map' => [
        'input' => '$replies',
        'in' => [
          '$mergeObjects' => [
            '$$this',
            [ 'is_liked' => [ '$in' => [ $user_id, '$$this.likes.user_id'  ] ] ]
          ]
        ]        
      ]
    ]
  ]],
  ... # any other pipeline
])

In both cases of course where $user_id is your PHP variable as the singular value in argument to $in, and where the '$$this.likes.user_id' is the MongoDB representation of the array of user_id values in that inner array. Note the array is the second argument and the singular is the first.

The $map operator uses the '$$this' to represent the current element of the array being processed. In both examples this allows re-mapping of the array content, just as the operator name implies.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for your detailed instructions. It gave the right result. Sorry for the late feedback.

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.