$map against $map?

This is a question inspired by the last optional lab of chapter 1. Spoiler alert if you want to figure out the answer on your own.

var pipeline=[
  {
    $project:{
      "writers":{
        $map:{
          input: "$writers",
          as: "writer",
          in:{
            $arrayElemAt:[
              { $split : [ "$$writer", " (" ] },
              0
            ]
          }
        }
      },
      "cast":{
        $map:{
          input: "$cast",
          as: "castMember",
          in:{
            $arrayElemAt:[
              { $split : [ "$$castMember", " (" ] },
              0
            ]
          }
        }
      },
      "directors":{
        $map:{
          input: "$directors",
          as: "dir",
          in:{
            $arrayElemAt:[
              { $split : ["$$dir", " ("] },
              0
            ]
          }
        }
      },
      "_id" : 0,
      "title" : 1
    }
  },
  {
    $project:{
      "allThree":{
        $size: { $setIntersection : ["$directors", "$writers", "$cast"] }
      },
      "title": 1
    }
  },
  {
    $match: { "allThree" : { $gt : 0 } }
  }
]

As you can see I have three project stages, each using $map against an array to perform $split operation against all items in the array.

What I am wondering is if it’s possible to use $map against $map to turn a three stage projection into a one stage projection. Something like…

var pipeline =[
  {
    $addFields:{
      "allThree":{
        $map:{
          input: ["$directors", "$writers", "$cast"],
          as: "array",
          in:{
            $map:{
              input: "$$array",
              as: "person",
              in:{
                $arrayElemAt:[
                  { $split : ["$$person", " ("] },
                  0
                ]
              }
            }
          }
        }
      }
    }
  }
]

I tried that out, and it basically combines writers, directions, and actors into a list of lists. But I can’t figure out what to do from there. I try to use $setIntersection, but I can’t get $setIntersection to compare the arrays at the right level.

Something like this:

   {
      $addFields: {
         allThree: {
            $setIntersection: [
               {
                  $map: {
                     input: "$writers",
                     as: "person",
                     in: {$arrayElemAt: [{$split: ["$$person", " (" ]}, 0]}
                  }   
               },
               {
                  $map: {
                     input: "$cast",
                     as: "person",
                     in: {$arrayElemAt: [{$split: ["$$person", " (" ]}, 0]}
                  }   
               },
               {
                  $map: {
                     input: "$directors",
                     as: "person",
                     in: {$arrayElemAt: [{$split: ["$$person", " (" ]}, 0]}
                  }   
               }
            ]
         }
      }
   }

As for what you were trying, the first problem is the input was an array of three arrays, and secondly, $setIntersection needs individual arrays to work with (like above).

An alternative method could be:

  1. $reduce
  2. the input part would be a $concatArrays of all three fields
  3. the in part would:
    a. $split by the delimiter
    b. use $cond and $in to do a conditional check for existence
    c. then $concatArrays to add the non existent item to the new array field

I think you’re referring to M121 Aggregation Framework instead of M220. Plus it’s not really a spoiler, it’s actually against forum guidelines, but in your case it would be difficult for learners to pick out parts of the answer :wink: