Full-Text Search


  • This article is about running a full-text search with a dynamic query.
    To learn how to run a full-text search using a static-index, see full-text search with index.

  • Use the search() method to query for documents that contain specified term/s within the text of the specified document field/s.

  • When running a full-text search with a dynamic query, the auto-index created by the server breaks down the text of the searched document field using the default search analyzer.
    All generated terms are lower-cased, so the search is case-insensitive.

  • Gain additional control over term tokenization by running a full-text search using a static-index, where the used analyzer is configurable.

  • A boost value can be set for each search to prioritize results. Learn more in boost search results.

  • User experience can be enhanced by requesting text fragments that highlight the searched terms in the results. Learn more in highlight search results.



Search for single term

const employees = await session
     // Make a dynamic query on 'Employees' collection    
    .query({ collection: "Employees" })
     // * Call 'search' to make a Full-Text search
     // * Search is case-insensitive
     // * Look for documents containing the term 'University' within their 'Notes' field
    .search("Notes", "University")
    .all();

// Results will contain Employee documents that have
// any case variation of the term 'university' in their 'Notes' field.
from "Employees"
where search(Notes, "University")

  • Executing the above query will generate the auto-index Auto/Employees/BySearch(Notes).

  • This auto-index will contain the following two index-fields:

    • Notes
      Contains terms with the original text from the indexed document field 'Notes'.
      Text is lower-cased and Not tokenized.

    • search(Notes)
      Contains lower-cased terms that were tokenized from the 'Notes' field by the default search analyzer (RavenStandardAnalyzer). Calling the search() method targets these terms to find matching documents.

Search for multiple terms

  • You can search for multiple terms in the same field in a single search method.

  • By default, the logical operator between these terms is OR.
    Specify AND explicitly To perform an 'and' operation between these terms.

AND:

const employees = await session
    .query({ collection: "Employees" })
     // * Pass multiple terms in a single string, separated by spaces.
     // * Pass 'AND' as the third parameter
    .search("Notes", "College German", "AND")
    .all();

// * Results will contain Employee documents that have BOTH 'College' AND 'German'
//   in their 'Notes' field.
//   
// * Search is case-insensitive.
from "Employees"
where search(Notes, "College German", and)

OR:

const employees = await session
    .query({ collection: "Employees" })
     // * Pass multiple terms in a single string, separated by spaces.
     // * Pass 'OR' as the third parameter (or don't pass this param at all) 
    .search("Notes", "University Sales Japanese", "OR")
    .all();

// * Results will contain Employee documents that have
//   either 'University' OR 'Sales' OR 'Japanese' within their 'Notes' field
//
// * Search is case-insensitive.
from "Employees"
where search(Notes, "University Sales Japanese")

Search in multiple fields

  • You can search for terms in different fields by making multiple search calls.

  • By default, the logical operator between consecutive search methods is 'OR'.
    This behavior can be modified. See examples below.

Default behavior between search calls:

const employees = await session  
    .query({ collection: "Employees" })
    .search("Notes", "French")
     // Operator OR will be used between the two 'Search' calls by default
    .search("Title", "President")
    .all();

// * Results will contain Employee documents that have:
//   ('French' in their 'Notes' field) OR ('President' in their 'Title' field)
//
// * Search is case-insensitive.
from "Employees"
where search(Notes, "French") or search(Title, "President")

const companies = await session
    .query({ collection: "Companies" })
    .whereEquals("Contact.Title", "Owner")
     // Operator AND will be used with previous 'where' predicate
     // Call 'openSubclause' to open predicate block
    .openSubclause()
    .search("Address.Country", "France")
     // Operator OR will be used between the two 'Search' calls by default
    .search("Name", "Markets")
     // Call 'closeSubclause' to close predicate block
    .closeSubclause()
    .all();

// * Results will contain Company documents that have:
//   ('Owner' as the 'Contact.Title')
//   AND
//   (are located in 'France' OR have 'Markets' in their 'Name' field)
//
// * Search is case-insensitive
from "Companies"
where Contact.Title = "Owner" and 
(search(Address.Country, "France") or search(Name, "Markets"))

AND search calls::

const employees = await session
    .query({ collection: "Employees" })
    .search("Notes", "French")
     // Call 'andAlso' so that operator AND will be used with previous 'search' call
    .andAlso()
    .search("Title", "Manager")
    .all();

// * Results will contain Employee documents that have:
//   ('French' in their 'Notes' field)
//   AND
//   ('Manager' in their 'Title' field)
//
// * Search is case-insensitive
from "Employees"
where search(Notes, "French") and search(Title, "Manger")

Negate search:

const employees = await session
    .query({ collection: "Employees" })
    .search("Notes", "French")
    .andAlso()
     // Call 'openSubclause' to open predicate block
    .openSubclause()
     // Call 'not' to negate the next search call
    .not()
    .search("Title", "Manager")
     // Call 'closeSubclause' to close predicate block
    .closeSubclause()
    .all();

// * Results will contain Employee documents that have:
//   ('French' in their 'Notes' field)
//   AND
//   (do NOT have 'Manager' in their 'Title' field)
//
// * Search is case-insensitive
from "Employees"
where search(Notes, "French") and
(exists(Title) and not search(Title, "Manager"))

Search in complex object

  • You can search for terms within a complex object.

  • Any nested text field within the object is searchable.

const companies = await session
    .query({ collection: "Companies" })
     // * Look for documents that contain:
     //   the term 'USA' OR 'London' in any field within the complex 'Address' object
    .search("Address", "USA London")
    .all();

// * Results will contain Company documents that are located either in 'USA' OR in 'London'.
// * Search is case-insensitive.
from "Companies"
where search(Address, "USA London")

Using wildcards

  • Wildcards can be used to replace:

    • Prefix of a searched term
    • Postfix of a searched term
    • Both prefix & postfix
  • Note:

    • Searching with a wildcard as the prefix of the term (e.g. *text) is less recommended,
      as it will cause the server to perform a full index scan.

    • Instead, consider using a static-index that indexes the field in reverse order
      and then query with a wildcard as the postfix, which is much faster.

const employees = await session
    .query({ collection: "Employees" })
     // Use '*' to replace one ore more characters
    .search("Notes", "art*")
    .search("Notes", "*logy")
    .search("Notes", "*mark*")
    .all();

// Results will contain Employee documents that have in their 'Notes' field:
// (terms that start with 'art')  OR
// (terms that end with 'logy') OR
// (terms that have the text 'mark' in the middle) 
//
// * Search is case-insensitive
from "Employees" where
search(Notes, "art*") or
search(Notes, "*logy") or
search(Notes, "*mark*")

Syntax

// Available overloads:
search(fieldName, searchTerms);
search(fieldName, searchTerms, operator);
Parameter Type Description
fieldName string Name of the field in which you search.
searchTerms string A string containing the term or terms (separated by spaces) to search for.
operator string Logical operator to use between multiple terms in the same Search method.
Can be AND or OR (default).