Full text search
Orchid ORM supports all the main capabilities of Postgres for the full text search.
To keep it performant, define a generated tsvector column, and create a special search index.
language
By default, the search language is English.
You can set a different default language in the createBaseTable config:
import { createBaseTable } from 'orchid-orm';
export const BaseTable = createBaseTable({
language: 'swedish',
});See the list of supported language configs with the SQL:
SELECT cfgname FROM pg_ts_config;When performing a search, you can override the default language:
db.table.search({
language: 'finnish',
in: 'body',
query: 'query',
});language also accepts a raw SQL.
The language can be stored in the column of this table, then you can use languageColumn to use this column for the search:
db.table.search({
// the table has `lang` column, use it for the search
languageColumn: 'lang',
in: 'body',
query: 'query',
});text vector to search in
The text to search in can be a simple string, or a raw SQL, or a text column, or multiple columns:
db.table.search({
// search in the given string
text: 'simply a string to search in',
query: 'query',
});
import { raw } from 'orchid-orm';
db.table.search({
// raw SQL: join text columns with space
text: raw`concat_ws(' ', title, body)`,
query: 'query',
});
db.table.search({
// search in a single text column
in: 'body',
query: 'query',
});
db.table.search({
// search in multiple columns, they are concatenated with `concat_ws` as shown above
in: ['title', 'body'],
query: 'query',
});
db.table.search({
// search in multiple columns with different weights. Weight can be A, B, C, or D
in: {
title: 'A',
body: 'B',
},
query: 'query',
});For better performance, define a generated column of tsvector type, and use it in the search with vector keyword:
db.table.search({
vector: 'titleAndBodyVector',
query: 'query',
});search query
Read about different search queries in this Postgres doc.
search method can accept one of the following queries:
query: corresponds towebsearch_to_tsqueryin Postgres, good to use by defaultplainQuery: corresponds toplainto_tsqueryphraseQuery: corresponds tophraseto_tsquerytsQuery: corresponds toto_tsquery
The query (websearch_to_tsquery) can work with any user input, while other query kinds require a specific format and will fail for invalid input.
Each query kind accepts a string or a raw SQL.
import { raw } from 'orchid-orm';
db.table.search({
vector: 'titleAndBodyVector',
// can accept raw SQL:
phraseQuery: raw`'The Fat Rats'`,
});order by search rank
Read about search ranking in this Postgres doc.
Set order: true to order results by the search rank:
db.table.search({
in: 'body',
query: 'query',
// will add ORDER BY ts_rank(to_tsvector('english', body)) DESC
order: true,
});To order with ts_rank_cd instead of ts_rank, set coverDensity: true:
db.table.search({
in: 'body',
query: 'query',
// will add ORDER BY ts_rank_cd(to_tsvector('english', body)) DESC
order: {
coverDensity: true,
},
});Other options are:
db.table.search({
in: 'body',
query: 'query',
order: {
// weights for D, C, B, A:
weights: [0.1, 0.2, 0.4, 1],
// by default, rank ignores the document length
// change rank behavior by providing here a special number
normalization: 32,
// it's possible to change the order direction:
dir: 'ASC', // DESC by default
},
});Giving the as alias for the search allows to set the ordering in the order method:
db.table
.search({
as: 'search',
in: 'body',
query: 'query',
})
.order({
// can be `search: true` for defaults
search: {
// same options as above
coverDensity: true,
weights: [0.1, 0.2, 0.4, 1.0],
normalization: 32,
dir: 'ASC',
},
});select highlighted text
Give the as alias for the search, and it becomes possible to select a text with highlights of the matching words or phrases:
db.table
.search({
as: 'search',
in: 'body',
query: 'query',
})
.select({
highlightedText: (q) => q.headline('search'),
});When searching in the generated tsvector column, need to provide a text source to the headline:
db.table
.search({
as: 'search',
vector: 'textVector',
query: 'query',
})
.select({
// `body` is a column name
highlightedText: (q) => q.headline('search', { text: 'body' }),
});text can be a raw SQL, here we are joining multiple columns:
import { raw } from 'orchid-orm';
db.table
.search({
as: 'search',
vector: 'titleAndBodyVector',
query: 'query',
})
.select({
highlightedText: (q) =>
q.headline('search', { text: raw`concat_ws(' ', title, body)` }),
});headline supports a string for options, see details in Postgres doc.
Provide a simple string or a raw SQL:
db.table
.search({
as: 'search',
in: 'body',
query: 'query',
})
.select({
highlightedText: (q) =>
q.headline('search', {
options:
'MaxFragments=10, MaxWords=7, MinWords=3, StartSel=<<, StopSel=>>',
}),
});