Did anyone complete an **Optional Lab - Expressions with $project** without using $setIntersection?

Hi everyone! In this topic I want to compare our solutions, because I have solved it in a different way without $setIntersection and got exactly correct answer. So if you solved it in a different way please share your solution here with “Hide details” option

Attention! below is my solution code, so if you want try to solve this Lab by yourself - don’t look at it

Solution
db.movies.aggregate([
  {
    $match: {
      cast: {
        $elemMatch: {
          $exists: true,
          $not: { $size: 0 }
        }
      },
      directors: {
        $elemMatch: {
          $exists: true,
          $not: { $size: 0 }
        }
      },
      writers: {
        $elemMatch: {
          $exists: true,
          $not: { $size: 0 }
        }
      }
    }
  },
  {
    $project: {
      _id: 0,
      cast: {
        $map: {
          input: "$cast",
          as: "actor",
          in: {
            $arrayElemAt: [
              {
                $split: ["$$actor", " ("]
              },
              0
            ]
          }
        }
      },
      directors: {
        $map: {
          input: "$directors",
          as: "director",
          in: {
            $arrayElemAt: [
              {
                $split: ["$$director", " ("]
              },
              0
            ]
          }
        }
      },
      writers: {
        $map: {
          input: "$writers",
          as: "writer",
          in: {
            $arrayElemAt: [
              {
                $split: ["$$writer", " ("]
              },
              0
            ]
          }
        }
      }
    }
  },

Here is the magic :)) Last stage

 {
        $project: {
          isTheSame: {
            $anyElementTrue: {
              $filter: {
                input: "$cast",
                as: "actor",
                cond: {
                  $and: [
                    { $in: ["$$actor", "$writers"] },
                    { $in: ["$$actor", "$directors"] }
                  ]
                }
              }
            }
          }
        }
      },
      { $match: { isTheSame: true } }
    ]);

$filter resolves to an array and $anyElementTrue gives me true if $and with two $in had put true at any position. Then simple $match in the last row

I got exactly 1597

2 Likes

Thank Dima_13149 for your sharing codes. it looks cool, I think behind the scene of $setIntersection is somewhat looking alike what you have done. It helps to eliminate lines of codes.

1 Like

Hi @TuanD
Yeah I think the same. But the fun is that I didn’t even know about $setIntersection when I was writing my code :slight_smile:
So I tried to implement the knowledge that I already know. But afterwards I have got a similar conclusion as you.

1 Like

Hi. I given a shot to complete the optional assignment without using the $setIntersection

The following is the query I used:

db.movies.aggregate( [ { $match: { writers: { $elemMatch: { $exists: true } }, directors: { $elemMatch: { $exists: true } }, cast : { $elemMatch: { $exists: true } } } }, { $project : { _id: 0, title : 1, cast: 1, writers: { $map: { input: “$writers”, as: “writer”, in: { $arrayElemAt: [ { $split: [ “$$writer”, " (" ] }, 0 ] } } } , directors : 1 } }, { $unwind : { path : ‘$cast’, includeArrayIndex: ‘cast_index’ }},{ $unwind : { path : ‘$writers’, includeArrayIndex: ‘writers_index’ } } ,{ $unwind : { path : ‘$directors’, includeArrayIndex: ‘directors_index’ } }, { $project : { title :1, compare_cast_directors : { $cmp : [’$cast’,’$directors’] }, compare_cast_writers : { $cmp : [’$cast’,’$writers’] }, compare_directors_writers: { $cmp : [’$directors’,’$writers’] } } }, { $match : { compare_cast_directors : 0, compare_cast_writers : 0, compare_directors_writers : 0 }}, { $group : {_id : “$title” } } ]).itcount()

Basically, I am trying to find out all the documents which has all the 3 entities(cast, directors, writers) and then remove the noise in writers entity and then unwinded the cast entity, directories entity, writers entity and then used $cmp operator to compare the cast, directors and writers for each document and if all 3 of them are 0, it means its a hit. Finally I did a group by title to avoid duplicates.

I came close and my query above is returning 1593 instead of 1597.

I tried to figure out the reason. But I couldn’t.

Can anyone point me the mistake in the above aggregation query which is causing to return 4 movies less.

regards,
Chakrapani

Hi @Chakrapani_68065
I have figured out that the problem is in your approach, clearly with

{ $group: { _id: "$title" } }

Try this request

db.movies.find({title: "It's Such a Beautiful Day"}).pretty()

and you’ll see that the result will be a two different films with the same actors and the same title (2011 and 2012 years). One is in the “Short” genre and another is in the “Comedy”.

So when you group films by the title at the final stage, then two different films becomes one (that’s why you lose your 4 films like in the example above).

2 Likes

Nice catch @Dima_13149.

1 Like

Why is my code wrong?

db.movies.aggregate([
{
$match: {
cast: {$elemMatch: {$exists: true}},
directors: {$elemMatch: {$exists: true}},
writers: {$elemMatch: {$exists: true}}
}
},
{
$project: {
writers: {
$map: {
input: “$writers”,
as: “writer”,
in: {
$arrayElemAt: [
{
$split: [ “$$writer”, " (" ]
},
0
]
}
}
},
directors: 1,
cast: 1,
_id: 0,
laborOfLove: {
$setIntersection: ["$writers","$directors","$cast"]
}
}
},
{
$match: {
laborOfLove: {$ne: null},
}
},
{
$match:{
laborOfLove: {$ne: }
}
}
]).itcount()

Hi @Guy_40297,

Please check your discourse inbox.

Thanks,
Sonali