npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@rohanadnan1/search-service

v0.0.2

Published

Plug-and-play NestJS search service with fuzzy, autocomplete, hybrid, and semantic vector search for MongoDB Atlas.

Readme

@rohanadnan1/search-service

Plug-and-play NestJS search service with fuzzy, autocomplete, hybrid, and semantic vector search for MongoDB Atlas.

npm version License: MIT


Features

  • 🔍 Text Search — Full-text search using MongoDB $text operator
  • 🪄 Fuzzy Search — Typo-tolerant search via MongoDB Atlas Search
  • Autocomplete — Prefix-based suggestions as the user types
  • 🔗 Hybrid Search — Combines fuzzy + text with automatic fallback
  • 🧠 Vector / Semantic Search — AI-powered meaning-based search using Cohere embeddings
  • 📦 Plug-and-Play — One import, one line of config
  • 🏗️ Multi-Tenant Ready — API key-based collection isolation

Quick Start (3 Steps)

1. Install

npm install @rohanadnan1/search-service

Peer dependencies — your NestJS project should already have these installed. If not:

npm install @nestjs/common @nestjs/core @nestjs/config @nestjs/mongoose mongoose reflect-metadata rxjs

For vector/semantic search, also install:

npm install cohere-ai

2. Import the Module

In your app.module.ts (or any NestJS module):

import { Module } from '@nestjs/common';
import { SearchServiceModule } from '@rohanadnan1/search-service';

@Module({
  imports: [
    SearchServiceModule.forRoot({
      mongoUri: 'mongodb+srv://user:[email protected]/mydb',
      cohereApiKey: 'your-cohere-api-key', // optional — only needed for vector search
    }),
  ],
})
export class AppModule {}

That's it. All search services, repositories, and controllers are now available in your app.

3. Use the Services

Inject any service you need:

import { Injectable } from '@nestjs/common';
import {
  SearchOrchestratorService,
  CollectionsService,
  EmbeddingsService,
  SearchType,
} from '@rohanadnan1/search-service';

@Injectable()
export class ProductSearchService {
  constructor(
    private readonly search: SearchOrchestratorService,
    private readonly collections: CollectionsService,
    private readonly embeddings: EmbeddingsService, // optional
  ) {}

  // Fuzzy search with typo tolerance
  async searchProducts(query: string) {
    return this.search.search({
      collectionName: 'products',
      query,
      searchType: SearchType.FUZZY,
      pagination: { limit: 20, page: 1 },
    });
  }

  // Autocomplete suggestions
  async autocomplete(query: string) {
    return this.search.search({
      collectionName: 'products',
      query,
      searchType: SearchType.AUTOCOMPLETE,
      pagination: { limit: 5 },
    });
  }
}

Configuration Options

SearchServiceModule.forRoot(options)

| Option | Type | Required | Default | Description | | ---------------- | -------- | -------- | ------------------------ | ---------------------------------------- | | mongoUri | string | ✅ | — | MongoDB connection URI | | dbName | string | ❌ | URI default | Database name | | cohereApiKey | string | ❌ | — | Cohere API key (for vector search) | | embeddingModel | string | ❌ | embed-english-v3.0 | Cohere embedding model | | isGlobalConfig | boolean| ❌ | true | Register ConfigModule globally |

SearchServiceModule.forRootFromEnv()

Reads config from environment variables — no options needed:

SearchServiceModule.forRootFromEnv()

| Env Variable | Required | Description | | ------------------------ | -------- | --------------------------- | | MONGO_URI | ✅ | MongoDB connection URI | | DB_NAME | ❌ | Database name | | COHERE_API_KEY | ❌ | Cohere API key | | EMBEDDING_MODEL | ❌ | Cohere model name | | EMBEDDINGS_CACHE_MAX_SIZE | ❌ | Max cache entries (default: 10000) |


Registering a Collection

Before you can search, register your MongoDB collection so the service knows which fields are searchable:

// Register via CollectionsService (programmatically)
const result = await collectionsService.registerCollection({
  collectionName: 'products',
  searchableFields: {
    text: ['name', 'description', 'brand'],     // required — at least one field
    autocomplete: ['name', 'brand'],             // optional
    filters: ['category', 'price', 'inStock'],   // optional
    sortable: ['price', 'rating', 'createdAt'],   // optional
  },
  searchDefaults: {
    fuzzyMaxEdits: 2,     // 0, 1, or 2 — typo tolerance
    limit: 20,            // default results per page
    minScore: 0.5,        // minimum relevance threshold
  },
});

// The response includes Atlas Search index templates
// Create these indexes in MongoDB Atlas Dashboard, then:
await collectionsService.markIndexesCreated('products');

Or use the REST API (auto-registered at /api/v1/collections):

# Register collection
curl -X POST http://localhost:3000/api/v1/collections \
  -H "Content-Type: application/json" \
  -d '{
    "collectionName": "products",
    "searchableFields": {
      "text": ["name", "description"],
      "autocomplete": ["name"]
    }
  }'

# Get index templates to create in Atlas
curl http://localhost:3000/api/v1/collections/products/templates

# Mark indexes as created
curl -X POST http://localhost:3000/api/v1/collections/products/indexes-created

Search Types

Text Search

Basic full-text search using MongoDB $text operator. Requires a text index on the collection.

const results = await search.search({
  collectionName: 'products',
  query: 'wireless headphones',
  searchType: SearchType.TEXT,
});

Fuzzy Search

Typo-tolerant search via MongoDB Atlas Search. Handles misspellings gracefully.

const results = await search.search({
  collectionName: 'products',
  query: 'wireles headfones',  // typos are OK!
  searchType: SearchType.FUZZY,
  fuzzyMaxEdits: 2,
});

Autocomplete

Prefix-based suggestions as the user types. Returns max 10 results.

const results = await search.search({
  collectionName: 'products',
  query: 'iph',  // matches "iPhone", "iPhone case", etc.
  searchType: SearchType.AUTOCOMPLETE,
  pagination: { limit: 5 },
});

Hybrid Search

Combines fuzzy search with text search fallback. Tries fuzzy first, falls back to text if Atlas Search is unavailable.

const results = await search.search({
  collectionName: 'products',
  query: 'laptop',
  searchType: SearchType.HYBRID,
});

Vector / Semantic Search

AI-powered meaning-based search. Finds results by meaning, not just keyword matching.

Prerequisites:

  1. Set cohereApiKey in module config
  2. Generate embeddings for your documents (see below)
  3. Create a vector search index in MongoDB Atlas
// Search by meaning
const results = await search.search({
  collectionName: 'products',
  query: 'something to listen to music wirelessly',
  searchType: SearchType.VECTOR,
});

// Generate embeddings for all documents in a collection
// POST /api/v1/embeddings/generate-for-collection
// { "collectionName": "products", "nameField": "name", "descriptionField": "description" }

Available Services

Everything is importable from the top-level package:

import {
  // Module
  SearchServiceModule,

  // Search
  SearchOrchestratorService,  // Main search orchestrator
  StrategyFactoryService,     // Get search strategy by type
  SearchType,                 // Enum: TEXT, FUZZY, AUTOCOMPLETE, VECTOR, HYBRID
  SearchRequestDto,           // Search request structure
  SearchResponseDto,          // Search response structure

  // Collections
  CollectionsService,         // Register/manage collections
  RegisterCollectionDto,      // Registration request structure
  UpdateCollectionDto,        // Update request structure

  // Database
  DatabaseService,            // Connection management & health checks
  BaseRepository,             // Generic CRUD for any collection
  SearchRepository,           // Search-specific operations
  AggregationRepository,      // Complex aggregations

  // Embeddings
  EmbeddingsService,          // Generate AI embeddings
  EmbeddingsCache,            // Embedding cache management
  CohereProvider,             // Cohere AI provider

  // Strategies (for advanced use)
  TextSearchStrategy,
  FuzzySearchStrategy,
  AutocompleteStrategy,
  HybridSearchStrategy,
  VectorSearchStrategy,
} from '@rohanadnan1/search-service';

REST API Endpoints

When you import SearchServiceModule, these endpoints are automatically available:

Search

| Method | Endpoint | Description | | ------ | ----------------------------- | ------------------------ | | POST | /api/v1/search | Execute a search | | POST | /api/v1/search/autocomplete | Autocomplete suggestions |

Collections

| Method | Endpoint | Description | | ------ | --------------------------------------------- | -------------------------- | | POST | /api/v1/collections | Register a collection | | GET | /api/v1/collections | List all collections | | GET | /api/v1/collections/:configId | Get collection config | | PATCH | /api/v1/collections/:configId | Update collection config | | DELETE | /api/v1/collections/:configId | Delete collection config | | POST | /api/v1/collections/:configId/indexes-created | Mark indexes as created | | GET | /api/v1/collections/:configId/templates | Get Atlas index templates |

Embeddings

| Method | Endpoint | Description | | ------ | ------------------------------------------------- | -------------------------- | | POST | /api/v1/embeddings/generate | Generate single embedding | | POST | /api/v1/embeddings/batch | Generate batch embeddings | | POST | /api/v1/embeddings/generate-for-collection | Embed all docs in collection | | GET | /api/v1/embeddings/info | Provider info & stats | | GET | /api/v1/embeddings/health | Check Cohere availability | | DELETE | /api/v1/embeddings/cache | Clear embedding cache |


Sub-Module Imports

You can also import individual modules if you only need specific functionality:

// Only database operations
import { DatabaseModule, DatabaseService, BaseRepository } from '@rohanadnan1/search-service/database';

// Only collection management
import { CollectionsModule, CollectionsService } from '@rohanadnan1/search-service/collections';

// Only embeddings
import { EmbeddingsModule, EmbeddingsService } from '@rohanadnan1/search-service/embeddings';

// Only search
import { SearchModule, SearchOrchestratorService, SearchType } from '@rohanadnan1/search-service/search';

Full Integration Example

Here's a complete example of integrating into an existing NestJS e-commerce backend:

// app.module.ts
import { Module } from '@nestjs/common';
import { SearchServiceModule } from '@rohanadnan1/search-service';
import { ProductsModule } from './products/products.module';

@Module({
  imports: [
    SearchServiceModule.forRoot({
      mongoUri: process.env.MONGO_URI!,
      cohereApiKey: process.env.COHERE_API_KEY, // optional
    }),
    ProductsModule,
  ],
})
export class AppModule {}
// products/products.service.ts
import { Injectable } from '@nestjs/common';
import {
  SearchOrchestratorService,
  CollectionsService,
  SearchType,
  BaseRepository,
} from '@rohanadnan1/search-service';

@Injectable()
export class ProductsService {
  constructor(
    private readonly search: SearchOrchestratorService,
    private readonly collections: CollectionsService,
    private readonly repo: BaseRepository,
  ) {}

  /**
   * One-time setup: register your collection
   * Call this once during app initialization
   */
  async setupSearch() {
    try {
      await this.collections.registerCollection({
        collectionName: 'products',
        searchableFields: {
          text: ['name', 'description', 'brand'],
          autocomplete: ['name'],
          filters: ['category', 'price'],
          sortable: ['price', 'rating'],
        },
      });
    } catch (error) {
      // Collection already registered — that's fine
    }
  }

  async searchProducts(query: string, page = 1) {
    return this.search.search({
      collectionName: 'products',
      query,
      searchType: SearchType.FUZZY,
      pagination: { limit: 20, page },
      filterOptions: {
        filters: { category: 'electronics' },
        sort: { price: 1 },
      },
    });
  }

  async getSuggestions(query: string) {
    return this.search.search({
      collectionName: 'products',
      query,
      searchType: SearchType.AUTOCOMPLETE,
      pagination: { limit: 5 },
    });
  }

  async findProduct(id: string) {
    return this.repo.findById('products', id);
  }
}
// products/products.controller.ts
import { Controller, Get, Query } from '@nestjs/common';
import { ProductsService } from './products.service';

@Controller('products')
export class ProductsController {
  constructor(private readonly productsService: ProductsService) {}

  @Get('search')
  async search(
    @Query('q') query: string,
    @Query('page') page?: string,
  ) {
    return this.productsService.searchProducts(query, Number(page) || 1);
  }

  @Get('suggest')
  async suggest(@Query('q') query: string) {
    return this.productsService.getSuggestions(query);
  }
}

MongoDB Atlas Setup

For fuzzy search and autocomplete, you need MongoDB Atlas Search indexes:

  1. Go to your MongoDB Atlas Dashboard
  2. Navigate to Database → Search
  3. Click Create Search Index
  4. Use the templates from GET /api/v1/collections/:configId/templates
  5. After creating, call POST /api/v1/collections/:configId/indexes-created

For vector search, also create a Vector Search index:

{
  "type": "vectorSearch",
  "fields": [
    {
      "type": "vector",
      "path": "embedding",
      "numDimensions": 1024,
      "similarity": "cosine"
    }
  ]
}

License

MIT © Rohan Adnan