M121 Optional Lab question

I would like some help with understanding the setIntersection: operator. It is my understanding that it will compare any number of arrays and return what is common…

This is easy to apply to two arrays… But if you have 3 or more, does it return based on “any” two instances of a common entry in an array? (an entry in array 1 matches array 3… or array 2 matching array 3… Or any combination of this)

I ran the following and I get a really interesting printout

 {$project: {"_id": 0, "cast": 1, "directors":1, "writers":1, "Common":{$setIntersection: [["$cast", "$directors", "$writers"]]}}},

This gives me the following output when I run
db.movies.aggregate(pipeline).pretty();

(of course I entered the above query in a var pipeline = [ espression.)

[
  {
    "cast": [
      "Jeanne d'Alcy",
      "Georges M�li�s"
    ],
    "directors": [
      "Georges M�li�s"
    ],
    "Common": [
      null,
      [
        "Georges M�li�s"
      ],
      [
        "Jeanne d'Alcy",
        "Georges M�li�s"
      ]
    ]
  },
  {
    "cast": [
      "Mrs. Auguste Lumiere",
      "Andr�e Lumi�re",
      "Auguste Lumi�re"
    ],
    "directors": [
      "Louis Lumi�re"
    ],
    "Common": [
      null,
      [
        "Louis Lumi�re"
      ],
      [
        "Mrs. Auguste Lumiere",
        "Andr�e Lumi�re",
        "Auguste Lumi�re"
      ]
    ]
  },

This is just two records but notice that both have a common array and the first entry is null… ?? So… what am I missing?

To I need to pull each array into the $project and perform a $split on the contents to remove anything other than the name?

Your brackets are wrong:

You have too many brackets. Now you are doing the intersection of a single array that has 3 elements. The intersection of one array will always be itself.

You get null because the specific documents has no field named writers. If you look at the output documents, despite the fact that you do project writers, it is not shown because it does not exists.

1 Like

Thanks… However I don’t think I understand this. Can you please either direct me to documentation or clarify for me?

I was under the understanding that IF the arrays passed to $setIntersection: had common elements, it would be listed in the field specified. Therefor with the command:


    {$project: {"_id": 0, "cast": 1, "directors":1, "writers":1,
 "Common":{$setIntersection: ["$cast", "$directors", "$writers"]}}},

The “Common” array or field should have the entries of any arrays that have common elements. Therefore based on this query:

[
  {
    "cast": [
      "Jeanne d'Alcy",
      "Georges M�li�s"
    ],
    "directors": [
      "Georges M�li�s"
    ],
    "Common": null
  },
  {
    "cast": [
      "Mrs. Auguste Lumiere",
      "Andr�e Lumi�re",
      "Auguste Lumi�re"
    ],
    "directors": [
      "Louis Lumi�re"
    ],
    "Common": []
  },
  {
    "cast": [
      "Georges M�li�s"
    ],
    "directors": [
      "Georges M�li�s"
    ],
    "Common": null
  },
  {
    "cast": [
      "Gaston M�li�s",
      "Georges M�li�s",
      "Georgette M�li�s"
    ],
    "directors": [
      "Georges M�li�s"
    ],
    "writers": [
      "Georges M�li�s"
    ],
    "Common": [
      "Georges M�li�s"
    ]
  },
  {
    "directors": [
      "�mile Reynaud"
    ],
    "Common": null
  },
  {
    "cast": [
      "Auguste Lumi�re"
    ],
    "directors": [
      "Louis Lumi�re"
    ],
    "Common": []
  },
  {
    "cast": [
      "Jeanne d'Alcy",
      "Georges M�li�s"
    ],
    "directors": [
      "Georges M�li�s"
    ],
    "writers": [
      "Georges M�li�s"
    ],
    "Common": [
      "Georges M�li�s"
    ]
  },
  {
    "cast": [
      "Charles Kayser",
      "John Ott"
    ],
    "directors": [
      "William K.L. Dickson"
    ],
    "Common": []
  },
  {
    "cast": [
      "Ella Lola"
    ],
    "directors": [
      "James H. White"
    ],
    "writers": [
      "George L. Du Maurier (novel)"
    ],
    "Common": []
  },
  {
    "cast": [
      "Fran�ois Clerc",
      "Beno�t Duval"
    ],
    "directors": [
      "Louis Lumi�re"
    ],
    "Common": []
  },
  {
    "cast": [
      "Georges M�li�s"
    ],
    "directors": [
      "Georges M�li�s"
    ],
    "writers": [
      "Georges M�li�s"
    ],
    "Common": [
      "Georges M�li�s"
    ]
  },
  {
    "cast": [
      "Georges M�li�s"
    ],
    "directors": [
      "Georges M�li�s"
    ],
    "Common": null
  },
  {
    "cast": [
      "Barral",
      "Bleuette Bernon",
      "Carmely",
      "Jeanne d'Alcy"
    ],
    "directors": [
      "Georges M�li�s"
    ],
    "writers": [
      "Charles Perrault (story)"
    ],
    "Common": []
  },
  {
    "cast": [
      "Harold Smith"
    ],
    "directors": [
      "George Albert Smith"
    ],
    "Common": []
  },
  {
    "cast": [
      "Georges M�li�s"
    ],
    "directors": [
      "Georges M�li�s"
    ],
    "writers": [
      "Georges M�li�s"
    ],
    "Common": [
      "Georges M�li�s"
    ]
  },
  {
    "cast": [
      "Laura Bayley",
      "Tom Green"
    ],
    "directors": [
      "George Albert Smith"
    ],
    "Common": []
  },
  {
    "cast": [
      "Fred Ott"
    ],
    "directors": [
      "William K.L. Dickson"
    ],
    "Common": []
  },
  {
    "cast": [
      "Thomas White"
    ],
    "directors": [
      "George S. Fleming",
      "Edwin S. Porter"
    ],
    "Common": []
  },
  {
    "directors": [
      "Edwin S. Porter"
    ],
    "Common": null
  },
  {
    "cast": [
      "Georges M�li�s"
    ],
    "directors": [
      "Georges M�li�s"
    ],
    "Common": null
  }
]

The results where there is an entry that is the same… IE the first result… The “Common” field should have Georges in it… right?

It is Null… Why?

I just looked at my results again… It appears that using the $setIngersection operator requires that all elements have an entry for it to be added to the field “Common”… From my reading, this is not what the documentation says.

Well… After reading this again… I am wrong… So… Can I use the $or statement to group the arrays into groups of two? Is this the way to compare each array against the other?

Example.
Cast to directors
Cast to writers
directors to writers
??

I believe this is the only array comparisons.

Thoughts/ Recommendations???

Using the above mentioned logic, I combined the arrays in an $or statement. the results are really interesting. Common returns either true or false… I was under the impression that common should contain entries of the elements that are common to any of the or combinations. My or statement is below.

"Common":{$or:[
        {$setIntersection: ["$cast", "$directors"]},
        {$setIntersection: ["$cast", "$writers"]},
        {$setIntersection: ["$directors", "$writers"]}]}}}

Returns…

{
    "cast": [
      "Gaston M�li�s",
      "Georges M�li�s",
      "Georgette M�li�s"
    ],
    "directors": [
      "Georges M�li�s"
    ],
    "writers": [
      "Georges M�li�s"
    ],
    "Common": true
  },
  {
    "directors": [
      "�mile Reynaud"
    ],
    "Common": false
  },

Common:true and Common:false

The result of a logical operator ($or) will be the logical values true or false. That’s why you get Common:true or Common:false. You are not projecting the intersections but the truthiness of intersections.

Common:[], Common:null and Common: [“Geor…s”]

It is clear that when the 3 arrays contain a common element we get the expected result. I do not know why sometimes you get [] and sometimes null. I was expecting to always get []. You could add a match stage to eliminate documents with empty/non existing cast,directors,writers arrays.