0

I have a like array that contains a list of users who like images embedded in the document. I want to return boolean value when user likes photo with the user_id parameter passed.

I use $eq aggregate but it only accepts the latest object of like array. If an array has only one object it will return the correct value, If the array has more than one object it will only look in the latest object. I have to do so that it can find all objects in like array and return the correct value.

"likes" : [ 
        {
            "user_id" : ObjectId("")
        }, 
        {
            "user_id" : ObjectId("")
        }
  ],

db.getCollection('photos').aggregate(
    [
        {
            $match: {
            status: '1'
            }
        },

        {
            $project: {
                like_count:{$size:"$likes"},
                is_liked: {$eq: ["$likes.user_id", [ObjectId("")]]},
                _id:1,
                title:1
            }
        },
    ]
);
5
  • Sorry but the requirement is not clear to me. Which of the following things do you want: 1. You will pass in a user ID and want to know how many photos did that user liked 2. You will pass in an array of user IDs and want to know how many photos did the specified users liked (including all) 3. You will pass in an array of user IDs and want to know how many photos any of the specified users liked? Commented Aug 25, 2019 at 9:38
  • I need to show if the user likes the photos. Then change the status of like button to liked. Commented Aug 25, 2019 at 10:14
  • Here the user is a single user? Commented Aug 25, 2019 at 10:24
  • User logged in. Commented Aug 25, 2019 at 10:59
  • okay. So for each photo, the user id of the logged-in user would be checked in likes array. Commented Aug 25, 2019 at 11:01

2 Answers 2

1

The following query can get us the expected output:

db.photos.aggregate([
    {
        $match:{
            "status":"1"
        }
    },
    {
        $project:{
            "_id":1,
            "title":1,
            "like_count":{
                $size:"$likes"
            },
            "is_liked":{
                $in:[{ "user_id" : ObjectId("5d626ad2f00e0c8c3593b60e") }, "$likes"]
            }
        }
    }
]).pretty()

Data set:

{
    "_id" : ObjectId("5d626b0bf00e0c8c3593b610"),
    "title" : "Cool",
    "status" : "1",
    "likes" : [
        {
            "user_id" : ObjectId("5d626ad2f00e0c8c3593b60e")
        },
        {
            "user_id" : ObjectId("5d626addf00e0c8c3593b60f")
        }
    ]
}

Output:

{
    "_id" : ObjectId("5d626b0bf00e0c8c3593b610"),
    "title" : "Cool",
    "like_count" : 2,
    "is_liked" : true
}

We are preparing a document from the user ID to search and checking if that document is present in likes array using $in operator.

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

5 Comments

Thank you. It's exactly what I want. I have one more question: I'm using push to add object to likes array and pull to remove object from it. I have to run a query to determine if the user exists then perform push or pull the user_id. Is there a way to do this in only a query?
@diepnt there is certainly a way :)... I would request you to post a new question as it would help devs who are having the same query.
@diepnt Added necessary comments on your other question. Also please upvote this answer if you found it useful :)
@Mr.S.Sharama I have a question on this topic: stackoverflow.com/questions/58039591/…
1

replace is_liked logic with this, in your query mongo will only match 1st element of array so you need to filter array to check the occurance of user_id and if filter returns non empty array liked true else false

{
    $project: {
      is_liked: {
        $cond: {
          if: {
            $gt: [
              {
                $size: {
                  $filter: {
                    input: "$likes",
                    as: "item",
                    cond: {
                      $eq: [
                        "$$item.user_id",
                        ObjectId("")                          ]
                    }
                  }
                }
              },
              0
            ]
          },
          then: true,
          else: false
        }
      }
    }
  }

3 Comments

Thank you. But your query is long and complicated. Do you have a shorter way? And I need fast performance because I use this query for many documents.
In your current db structure that's fastest way to calculate (have you tried above logic considering query response time) else you have to make changes to mongoplayground.net/p/blk5NMELbSi
Thank you. I use the way of Mr.S.Sharma. It's simple with newbie like me. I will study your way.

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.