home / skills / hoangnguyen0403 / agent-skills-standard / search

search skill

/skills/nestjs/search

This skill helps you implement robust NestJS search with CQRS, Elasticsearch indexing, and reliable event-driven synchronization patterns.

npx playbooks add skill hoangnguyen0403/agent-skills-standard --skill search

Review the files below or copy the command above to add this skill to your agents.

Files (1)
SKILL.md
1.7 KB
---
name: NestJS Search & CQRS
description: Elasticsearch integration and Sync patterns.
metadata:
  labels: [nestjs, search, elasticsearch, cqrs]
  triggers:
    files: ['**/*.service.ts', '**/search/**']
    keywords: [Elasticsearch, CQRS, Synchronization]
---

# Search Engine & Full-Text

## **Priority: P1 (OPERATIONAL)**

Full-text search implementation with Elasticsearch and database patterns.

- **Pattern**: **CQRS (Command Query Responsibility Segregation)**.
  - **Write**: To Primary Database (Postgres/MySQL). Source of Truth.
  - **Read (Complex)**: To Search Engine (Elasticsearch, OpenSearch, MeiliSearch). Optimized for filtering, fuzzy search, and aggregation.

## Synchronization (The Hard Part)

- **Dual Write (Anti-Pattern)**: `await db.save(); await es.index();`.
  - _Why_: Partial failures leave data inconsistent. Slows down HTTP response.
- **Event-Driven (Recommended)**:
  1. Service writes to DB.
  2. Service emits `EntityUpdated`.
  3. Event Handler (Async) pushes to Queue (BullMQ).
  4. Worker indexes document to Search Engine with retries.
- **CDC (Golden Standard)**: Change Data Capture (Debezium). Connects directly to DB transaction log. No app conceptual overhead, but higher ops complexity.

## Organization

- **Module**: Encapsulate the client in a `SearchModule`.
- **Abstraction**: Create generic `SearchService<T>` helpers.
  - `indexDocument(id, body)`
  - `search(query, filters)`
- **Mapping**: Use `class-transformer` to map Entities to "Search Documents". Search docs should be flatter than Relational entities constraints.

## Testing

- **E2E**: Do not mock the search engine in critical E2E flows.
- **Docker**: Spin up `elasticsearch:8` container in the test harness to verify indexing works.

Overview

This skill provides a practical NestJS guide for integrating full-text search using Elasticsearch and implementing CQRS-based sync patterns. It focuses on reliable indexing, modular organization, and operational patterns that avoid common consistency pitfalls. The guidance targets TypeScript/NestJS services and includes testing and deployment recommendations.

How this skill works

The skill recommends keeping the relational database as the source of truth and routing complex read scenarios to a search engine optimized for filtering and fuzzy queries. It promotes event-driven synchronization: write to DB, emit domain events, enqueue indexing jobs, and let resilient workers update Elasticsearch with retries. It also outlines CDC as an alternative for zero-application overhead synchronization.

When to use it

  • When you need fast, fuzzy, or aggregated reads that a relational DB cannot handle efficiently
  • When search relevance and complex filtering must be separated from primary transactional flows
  • When eventual consistency between DB and search engine is acceptable and desired
  • When you want robust retries and failure handling for indexing
  • When you need testable, modular search integration in NestJS

Best practices

  • Avoid dual-write in request flow; never do db.save() followed directly by es.index() in the same HTTP request
  • Use event-driven flow: DB write -> domain event -> queue -> worker indexes with retry and monitoring
  • Encapsulate search logic in a SearchModule and provide a generic SearchService<T> API
  • Map entities to flattened search documents using class-transformer to simplify indexing and queries
  • For critical E2E tests, run a real Elasticsearch container (e.g., elasticsearch:8) instead of mocking
  • Consider Debezium CDC for absolute correctness when operational complexity is acceptable

Example use cases

  • E-commerce product catalog where fast faceted search and fuzzy matching are required
  • Content platforms that need full-text search with relevance scoring and aggregations
  • Audit or analytics views that rely on denormalized, searchable documents derived from relational models
  • Microservices that emit domain events and push indexing jobs to BullMQ workers
  • CI test suites that spin up Elasticsearch to validate indexing and search behavior

FAQ

Why is dual-write considered an anti-pattern?

Dual-write in the request path can leave DB and search engine inconsistent on partial failures and it increases request latency.

When should I choose CDC over event-driven sync?

Choose CDC when you need guaranteed capture of every DB change without relying on application events and you can tolerate the extra operational complexity.