karthick
karthick

Reputation: 6158

Text search - mongodb

I am using mongo text search in my application.

Index:

db.test.createIndex(
    {
        title: 'text',
        description: 'text'
    },
    {
        name: "TextIndex",
        weights: {
           title: 10,
           description: 1
        }
    }
)

Score:

title : 10
description : 1

Document:

db.test.insert(
  [
    { _id: 1, title: "agent de production", description: "production or agent"},
    { _id: 2, title: "agent test production", description: "agent" },
    { _id: 3, title: "production agent", "description" : "production"},
    { _id: 4, title: "agent", "description" : "production"},
    { _id: 5, title: "test", "description" : "production example agent"},
  ]
)

Question

So if I search "agent production"

Result should be

[
  { _id: 1, title: "agent de production", description: "production or agent"},
  { _id: 2, title: "agent test production", description: "agent" },
  { _id: 3, title: "production agent", "description" : "production"},
  { _id: 5, title: "test", "description" : "production example agent"},
]

What i had tried:

db.test.find({"$text" : {"$search" : "\"agent production\""}}); Query result does not match with the expected result.

Result : Nil

Query phrase : db.test.find({"$text" : {"$search" : "\"agent\" \"production\""}})

Result :

{ "_id" : 5, "title" : "test", "description" : "production example agent" }
{ "_id" : 1, "title" : "agent de production", "description" : "production or agent" }
{ "_id" : 3, "title" : "production agent", "description" : "production" }
{ "_id" : 2, "title" : "agent test production", "description" : "agent" }
{ "_id" : 4, "title" : "agent", "description" : "production" }

Any suggestion will be grateful.

Upvotes: 1

Views: 376

Answers (1)

logan rakai
logan rakai

Reputation: 2557

Let's review how the $search string in the $text query works. If a phrase is given, as in "$search": "\"agent production\"", only documents with indexed fields matching the phrase receive a non-zero score. That explains why no results were found in this case. However specifying "$search": "\"production agent\"" would match the document with _id: 3. If individual words/terms are given, as in "$search": "\"agent\" \"production\"", any document with indexed fields matching any of the terms receive a score. This explains why document with _id: 4 is returned since it has the individual terms not necessarily both terms in a single field, as you have shown in your desired result.

To enforce that both search terms are included in a single field, you need to add additional clauses to the query. You can perform the text search for scoring the documents and filter them further using regex as in:

db.test.find( { $and: [ { "$text": { "$search": "\"agent\" \"production\"" } },
    { $or: [
        { $and: [ { title: /agent/i }, { title: /production/i } ] }, 
        { $and: [ { description: /agent/i }, { description: /production/i } ] }
    ] }
 ] }, { score: { $meta: "textScore" } } ).sort( { score: { $meta: "textScore" } } )

Note that the textScore is added because the documents are not sorted based on score by default.

Upvotes: 2

Related Questions