Returning Scored Results from Atlas Search Across Multiple Fields

Hello MongoDB,

I would like to run a compound search query which returns relevant results, but at the moment my query is returning every result and I don’t understand why. My issue/problem is that the search-term may be contained in a number of fields, and therefore I can’t stipulate a ‘must’ contain in the query.

Let’s say my data looks like this:

{
    restaurantName: String, //SAMPLE 'The Serenity'
    restaurantTitle: String, //SAMPLE 'Gorgeous vegan restaurant with river views'
    restaurantDesc: String, //SAMPLE 'The Serenity is a three-michelin-starred restaurant in the heart of Soho...'
    restaurantType: String //SAMPLE 'Chinese'
    area: String //SAMPLE 'Mayfair'
    city: String // SAMPLE 'London'
    country: String // SAMPLE 'UK"
}

At the moment my query is as follows (once this bit works I will obviously build it out). I’m just trying with two fields and a ‘should’ condition, I thought meaning return a result if the searchTerm is in either:

$search: {
            index: 'defaultRestaurantSearch',
                    compound: {
                        should: [
                            {
                                text: {
                                    query: req.query.searchTerm,
                                    path: 'restaurantTitle',
                                    fuzzy: {},
                                    score: {
                                        boost: {
                                            value: 9,
                                        },
                                    },
                                },
                            },
                            {
                                text: {
                                    query: req.query.searchTerm,
                                    path: 'restaurantDescription',
                                    fuzzy: {},
                                    score: {
                                        boost: {
                                            value: 8,
                                        },
                                    },
                                },
                            },
                        ],
                    },
                },

In the app there’s already a filtering system to allow users to filter restaurants. However, we would like to have an open text field search where we can basically expect users to type anything, from the restaurant name to something such as ‘chinese in Soho’.

At the moment, if I just enter ‘West End’ into the field, all records are returned, even those with no mention of Soho in the name, title, description, area etc…

Is there an obvious error in the code? Or is this even possible? I have been studying the sample Restaurant app at https://www.atlassearchrestaurants.com/ to get a feel for the compound query (even though the use-cases are slightly different) but I can’t get it to work.

I thought the problem may be with the Index Definition, and have tried both

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

and

{
  "mappings": {
    "dynamic": false,
    "fields": {
      "restaurantName": [
        {
          "dynamic": true,
          "type": "document"
        },
        {
          "type": "string"
        }
      ],
      "restaurantTitle": [
        {
          "dynamic": true,
          "type": "document"
        },
        {
          "type": "string"
        }
      ],
      ...//OTHER FIELDS HERE
    }
  }
}

But neither have made a difference.
I’ve used Atlas search a number of times before, but more simple searches on a single name field. Any help would be very much appreciated.

Cheers,
Matt

Hiya! Can you tell me more about the results and your expectations?

Are there results returning with Soho at all? Are they boosted to the top? Or are there other results appearing at the top that don’t include Soho at all?

Is the issue that there are results that don’t include SoHo appearing?

Hello Elle,

Thank you for your reply.

I’ve just edited the original question to change the search term to ‘West End’, as a bit more investigating this end has shown it’s something to do with spaces in the searchTerm.

I would like back an array of records where, in the above example, ‘West End’ is in either the restaurantTitle or restaurantDescription, but I’m getting an array of all the records in the collection. Further down the line I would like to expand the search to the ‘area’ field for example, which would be a more natural fit for ‘West End’, but I’m just trying to get it to work with two fields at the moment.

EDIT: Further testing has revealed if I search for ‘West’ or ‘End’ instead of ‘West End’ it does return only those records where the phrase ‘West End’ is in the restaurantTitle or restaurantDescription, but ‘West End’ with the space returns all the records.

Cheers,
Matt

Hi Matt, thanks for sharing your newest findings!

Can you try adding the minimumShouldMatch parameter to the compound query to ensure that the results match at least one 1 of the should clauses?

Additionally, if you want an exact match on the query, that can be achieved using the phrase operator instead of text in your query. The slop parameter achieves a similar effect to fuzzy. You can also read more about exact matches here.

Hope this helps!

2 Likes

Hello Amyjian,

Thank you for your reply, this has worked. The ‘phrase’ operator is exactly what I was looking for, which I wasn’t aware off, and becomes really powerful when used with the ‘slop’ parameter.

Thanks again,
Matt

2 Likes

This topic was automatically closed 5 days after the last reply. New replies are no longer allowed.