Home > Mobile >  how to match _id and perticular array element in mongodb without using unwind
how to match _id and perticular array element in mongodb without using unwind

Time:02-18

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.

CodePudding user response:

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

CodePudding user response:

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"]}
      }
    }
  }
}]
  • Related