0

I am working with MongoDB aggregation framework:-

I have a movie collection database which looks like this:-

{'_id': ObjectId('573a1390f29313caabcd4192'),
  'title': 'The Conjuring of a Woman at the House of Robert Houdin',
  'year': 1896,
  'runtime': 1,
  'cast': ["Jeanne d'Alcy", 'Georges M�li�s'],
  'plot': 'A woman disappears on stage.',
  'fullplot': 'An elegantly dressed man enters through a stage door onto a set with decorated back screen, a chair and small table. He brings a well-dressed women through the door, spreads a newspaper on the floor, and places the chair on it. She sits and fans herself; he covers her with a diaphanous cloth. She disappears; he tries to conjure her back with incomplete results. Can he go beyond the bare bones of a conjuring trick and succeed in the complete reconstitution of a the lady?',
  'lastupdated': '2015-08-26 00:05:55.493000000',
  'type': 'movie',
  'directors': ['Georges M�li�s'],
  'imdb': {'rating': 6.3, 'votes': 759, 'id': 75},
  'countries': ['France'],
  'genres': ['Short'],
  'tomatoes': {'viewer': {'rating': 3.7, 'numReviews': 59},
   'lastUpdated': datetime.datetime(2015, 9, 11, 17, 46, 29)}}

I have written the query:-

'$project': {
    'num_favs' : { 
        '$setIntersection' : [favorites, '$cast']
    },
    'tomatoes.viewer.rating' : 1,
    'title' : 1
}

It will return the set intersection of favorites array and cast field of my data along with 2 other fields. My favorites array looks like this:-

favorites = [
  "Sandra Bullock",
  "Tom Hanks",
  "Julia Roberts",
  "Kevin Spacey",
  "George Clooney"
]

What I want is that the field num_favs to be the size of the set returned by $setIntersection method.

I am unable to figure out how to find the size of the returned set. Can anyone please provide me with a solution to this?

Dhaval Taunk
  • 1,662
  • 1
  • 9
  • 17
  • Does this answer your question? [MongoDB: count the number of items in an array](https://stackoverflow.com/questions/21387969/mongodb-count-the-number-of-items-in-an-array). As stated in that link you need to use `$size`, check out this link to test it - I've added it your query :: https://mongoplayground.net/p/I_8arTA9No2 – whoami - fakeFaceTrueSoul May 23 '20 at 19:12
  • You can use [`$size`](https://docs.mongodb.com/manual/reference/operator/aggregation/size/) operator for this. But, when I was trying your `$project`, it's giving me an empty array for `num_favs` field, is this happening with you? Could you check? – ngShravil.py May 23 '20 at 19:57
  • Yes, I have used `$size` and in some cases, it will give and empty array because of no common element in `favorites` array and `$cast` field. Is there any way to ignore these `null arrays` and then find the size of the `num_favs`. – Dhaval Taunk May 24 '20 at 04:34
  • @whoami, You query is not working for me. It is giving me the error - `OperationFailure: The argument to $size must be an array, but was of type: null`. – Dhaval Taunk May 24 '20 at 04:42
  • 2
    @DhavalTaunk : That's because of your data !! First you need to do a little bit of research on your data, that query would work well with given dataset. I strongly believe there are docs where you don't have `cast` field if that's the case then your `$setIntersection` would return `null` that' why `$size` is failing, If you wanted to exclude docs which doesn't have `cast` field just add `$match: {cast : {$exists : true}}` as first stage else if you still wanted to return docs which doesn't have `cast` field & only do this `$size` thing on `cast` available docs then let me know.. – whoami - fakeFaceTrueSoul May 24 '20 at 04:47
  • 1
    @whoami, Yes I was making that mistake. This solved my issue. Thanks – Dhaval Taunk May 24 '20 at 04:54

1 Answers1

0

This will give the required result.

    db.movies.aggregate([
    {
      $match: {
          cast: {
            $in: favorites
            }
        }
   },
  {
    $project: {
        num_favs: {
            $size: {
                $setIntersection: [favorites, '$cast']
            }
        },
        "tomatoes.viewer.rating": 1,
        title: 1
    }
  }
])