DEV Community

Cover image for Full-Text Search: A Practical Guide for Node.js, TypeORM & PostgreSQL
Isaac Shosanya
Isaac Shosanya

Posted on Edited on

Full-Text Search: A Practical Guide for Node.js, TypeORM & PostgreSQL

Full-text search is a technique used to analyze strings, documents, or entire database columns to deliver flexible and intelligent search results. Instead of relying on string matching, full-text search looks at context, synonyms, and word variations.

So while a regular SQL query might match only "run", a full-text search can also match "running", "ran", or "runner" depending on the configuration.

Full-text search is supported by many databases including PostgreSQL, MySQL, MongoDB, and specialized engines like Elastic-search and Meilisearch.

In this article, we focus on PostgreSQL full-text search using TypeORM + Node.js.

Benefits of full-text search

  1. Search Large Bodies of text quickly: If you have large text fields, like blog posts, recipes, product descriptions, or comments, full-text search lets you efficiently check which documents contain certain keywords.

    Example: Search for "chicken" → return all recipes that mention chicken anywhere in the text.

  2. Better and more flexible search results: Full-text search handles imperfections in queries:

    • Typing "run shoes" can still match "running shoes"
    • Searching "comput" can match "computer" and "computing"

    This dramatically improves user experience on e-commerce, blogs, dashboards, and enterprise search tools.

When to use full-text search?

  1. You want flexibility, not exact matches; Searching products, users, notes, events, or blog posts where partial matches are okay.
  2. When you want to index large bodies of text and return results based on if a certain word or keyword is contained within that body of text ( returning a list of recipes that contain chicken).

Setting up full-text search in typeorm + postgres + nodejs

Below is an example using a simple Recipe entity that supports searching on both the name and description fields.

  1. Create the Recipe Entity
@Entity()
export class Recipe {
    @PrimaryGeneratedColumn()
    id: number;

    @Index({fulltext: true})
    @Column("varchar")
    name: string;

    @Index({fulltext: true})
    @Column("varchar")
    description: string;
}
Enter fullscreen mode Exit fullscreen mode
  1. Query the database using a the typeorm query-builder to return data based on the provided search query
async function searchRecipes(searchQuery: string) {
  return dataSource
    .getRepository(Recipe)
    .createQueryBuilder("recipe")
    .where(`
      to_tsvector('english', recipe.name || ' ' || recipe.description)
      @@ plainto_tsquery('english', :query)
    `)
    .setParameter("query", searchQuery)
    .getMany();
}

Enter fullscreen mode Exit fullscreen mode

In raw SQL this would look something like this

SELECT *
FROM recipe 
WHERE to_tsvector(name || " " || description) @@ to_tsquery("Chicken");
Enter fullscreen mode Exit fullscreen mode

This will then return all the recipes with chicken in it’s description or name

Top comments (3)

Collapse
 
prudentbird profile image
Prudent Bird •

very detailed!

Collapse
 
tobs_dl profile image
Oluwatobi O •

Nice read

Collapse
 
samuel_tuoyo profile image
OritseWeyinmi Samuel Tuoyo •

Nice read