Home > Enterprise >  MongoDb score results based on simple matches
MongoDb score results based on simple matches

Time:01-10

I'm trying to create a simple search algorithm that will try to match against a first name, last name, and/or set of tags, as an example:

[
  {
    "key": 1,
    "fname": "Bob",
    "lname": "Smith",
    "tags": [
      "a",
      "b",
      "c"
    ]
  },
  {
    "key": 2,
    "fname": "John",
    "lname": "Jacob",
    "tags": [
      "c",
      "d",
      "e"
    ]
  },
  {
    "key": 3,
    "fname": "Will",
    "lname": "Smith",
    "tags": [
      "a",
      "b",
      "c"
    ]
  }
]

This works with the following, but I can only get the tags count. Basically what I'm going for here is to match first-name, last-name, or tags and for each match store a "point":

db.collection.aggregate([
  {
    $match: {
      $or: [
        {
          "fname": "Will"
        },
        {
          "lname": "Smith"
        },
        {
          tags: {
            $in: [
              "b",
              "c"
            ]
          }
        }
      ]
    }
  },
  {
    $project: {
      tagsMatchCount: {
        $size: {
          "$setIntersection": [
            [
              "b",
              "c"
            ],
            "$tags"
          ]
        }
      }
    }
  },
  {
    "$sort": {
      tagsMatchCount: -1
    }
  }
])

Here's the sandbox I'm playing with: https://mongoplayground.net/p/DFJQZY-dfb5

CodePudding user response:

Query

  • create a document to hold the matches each in separate field
  • add one extra field total
  • keep only those with at least 1 match
  • you can sort also after by any of the 3 types of matches or by total, like
    {"$sort":{"points.total":-1}}
  • if you have index that can be used, remove my $match and add your match as first stage like in your example

Test code here

aggregate(
[{"$set":
  {"points":
   {"fname":{"$cond":[{"$eq":["$fname", "Will"]}, 1, 0]},
    "lname":{"$cond":[{"$eq":["$lname", "Smith"]}, 1, 0]},
    "tags":{"$size":{"$setIntersection":["$tags", ["b", "c"]]}}}}},
 {"$set":
  {"points.total":
   {"$add":["$points.fname", "$points.lname", "$points.tags"]}}},
 {"$match":{"$expr":{"$gt":["$points.total", 0]}}}])
  •  Tags:  
  • Related