Skip to content
Advertisement

How to find a document with an array of strings based on if it has items in common with a reference array of string?

Given a reference array of strings: ["Comedy", "Horror", "Romance"], I would like to query a Movie model with this schema:

const MovieSchema = new Schema({
    _id: {
        type: Types.ObjectId,
        required: true
    },
    title: {
        type: String,
        required: true
    },
    categories: [{ type: String }],
});

Such that I will get results where I will get Movies with categories in common with the reference array, sorted by the amount of elements it has in common with the reference array. For example:

[
    {
        _id: "57",
        title: "Sample Movie A",
        categories: ["Comedy", "Horror", "Romance", "Family"]
    },
    {
        _id: "92",
        title: "Sample Movie B",
        categories: ["Comedy", "Romance", "Family", "Coming of Age"]
    }
]

Note that Movie A is the first in the results because it has 3 items in common with the reference array while Movie B only has 2 items in common.

How can I achieve this query using Mongoose 5.11.16?

Advertisement

Answer

You could use $setIntersection to get a count of matching elements, add the resulting array-size as a new field to each document and and then sort by this field.

You could then extend the query to filter matches with a count greater than 0 and remove the categoryCount from the output, e.g.

Movie.aggregate([
  {
    "$addFields": {
      "categoryCount": {
        $size: {
          $setIntersection: [
            [
              "Comedy",
              "Horror",
              "Romance"
            ],
            "$categories"
          ]
        }
      }
    }
  },
  {
    "$match": {
      categoryCount: {
        $gt: 0
      }
    }
  },
  {
    "$sort": {
      categoryCount: -1
    }
  },
  {
    "$project": {
      categoryCount: 0
    }
  }
])

Example on mongoplayground: https://mongoplayground.net/p/ZlUNfB82FRK

User contributions licensed under: CC BY-SA
8 People found this is helpful
Advertisement