diepnt
diepnt

Reputation: 39

How to use $in in array of embed array mongodb

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.

Upvotes: 1

Views: 64

Answers (1)

Neil Lunn
Neil Lunn

Reputation: 151132

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.

Upvotes: 3

Related Questions