Sorting $search results

Hi

I created a search index containing 2 text fields and 1 number field.
Document look like this:

{
CompanyName: "Test 1",
CompanyKeywords: "key1, key2, key3",
CompanyScore: 454.44
},
{
CompanyName: "Test 2",
CompanyKeywords: "key1, key2, key3",
CompanyScore: 51.44
},

I need to sort the result of the $search by the CompanyScore field.
When I search for “Test” it brings “Test 2”, but I want it to sort by CompanyScore and bring “Test 1” as it should.

Please share the code you’ve used for your query and sorting.

Hello, @Forie_Forie :wave:

To better understand your situation, I extended your example dataset a bit, so it would look like this:

db.companiesRating.insertMany([
  {
    _id: 'A',
    companyName: 'Test 1',
    companyScore: 500,
  },
  {
    _id: 'B',
    companyName: 'Test 2',
    companyScore: 40,
  },
  {
    _id: 'C',
    companyName: 'Test 3',
    companyScore: 1500,
  },
  {
    _id: 'D',
    companyName: 'Test 4',
    companyScore: 99,
  }
]);

And created a simple Atlas Search index, named companied-search-test, with a default configuration:

{
  "mappings": {
    "dynamic": true
  }
}

Then, I used $search stage with “test” query in the aggregation pipeline to reproduce your case:

db.companiesRating.aggregate([
  {
    $search: {
      index: 'companies-search-test',
      text: {
        query: 'test',
        path: 'companyName'
      }
    }
  }
]);

Output:

[
  { _id: 'D', companyName: 'Test 4', companyScore: 99 },
  { _id: 'C', companyName: 'Test 3', companyScore: 1500 },
  { _id: 'A', companyName: 'Test 1', companyScore: 500 },
  { _id: 'B', companyName: 'Test 2', companyScore: 40 }
]

We can see, that documents order in the output is more random, than predictable.

To make it more predictable, you need add some additional logic that would modify document’s search score in the aggregation pipeline, like this:

db.companiesRating.aggregate([
  {
    $search: {
      index: 'companies-search-test',
      text: {
        query: 'test',
        path: 'companyName',
        score: {
          function:{
            multiply: [
              {
                path: {
                  value: 'companyScore',
                  undefined: 1
                }
              },
              {
                score: 'relevance'
              }
            ]
          }
        }
      }
    }
  },
  // this last $addFields stage is added to display the modified score
  // and can be removed
  {
    $addFields: {
      documentScore: { $meta: 'searchScore' },
    }
  }
]);

Output:

[
  {
    _id: 'C',
    companyName: 'Test 3',
    companyScore: 1500,
    documentScore: 71.83670806884766
  },
  {
    _id: 'A',
    companyName: 'Test 1',
    companyScore: 500,
    documentScore: 23.94556999206543
  },
  {
    _id: 'D',
    companyName: 'Test 4',
    companyScore: 99,
    documentScore: 4.741222858428955
  },
  {
    _id: 'B',
    companyName: 'Test 2',
    companyScore: 40,
    documentScore: 1.9156455993652344
  }
]

Now, the sorting of the documents is greatly affected by companyScore.