0

user data includes :

"_id" : 4
"username" : "smith"
likedVideos :[
           "videoId" : 10
           "title" : "something"
           "speaker" : "something"
           "description" : "something"
         ]

i have a collection with userId and a array of liked videos lists.liked videos(Array) includes videoId and video details. so i need to check that is the user is already liked this video or not. so how i match userId and videoId from the collection without using unwind ?

i tried :

  1. const data = await userModel.findOne({ _id : userId,likedVideos: { $elemMatch: { videoId : videoId } } }) but it returns all the data of that user.

  2. const alreadyLiked = await userModel.aggregate([ { $match: { '_id' : userId, 'likedVideos.videoId' : videoId, }, }, ]);

this also not working as expected.

I need a perfect solution to match a element inside array without using unwind (My boss said that unwind is a costly operation it will effect the app performance). can you please help me to solve this.

1
  • Can you provide a valid JSON example document? Also, is something like this what are you looking for? Commented Feb 18, 2022 at 10:23

2 Answers 2

1

Both of your queries are valid. It will return all the users that match your query. You are matching a specific user and a movie. So if a user is returned, it means that the user has already liked the video.

Nevertheless $elemMatch is useful when you have multiple conditions to apply to an object. So it's better to use your second solution with

{
  "_id": userId,
  "likedVideos.videoId": videoId
}

If you want to keep only a given element in likedVideos, you can use $filter in an aggregate.

For example

db.collection.aggregate([
  {
    $match: {
      "_id": 1
    }
  },
  {
    $project: {
      list: {
        $filter: {
          input: "$likedVideos",
          as: "item",
          cond: {
            $eq: [
              "$$item.videoId",
              1
            ]
          }
        }
      }
    }
  }
])

it will only return the movies in likedVideoswith id=1

try it here

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

Comments

1

The best way to filter elements in a subarray is by using an Aggregation with $match and $project.

Example:

[{
  $match: { 
    _id: 'userId',
    likedVideos.videoId: 'videoId'
  }
}, {
  $project: {
    'likedVideos': {
      $filter: {
          input: '$likedVideos',
          as: 'item',
          cond: 
             {$eq: ["$$item.videoId","videoId"]}
      }
    }
  }
}]

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.