Skip to content

A powerful, zero-dependency filtering library that brings MongoDB-style operators, SQL wildcards, and intelligent autocomplete to TypeScript arrays. Think of it as Array.filter() on steroids! ๐Ÿ’ช

License

Notifications You must be signed in to change notification settings

mcabreradev/filter

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

@mcabreradev/filter

Filter arrays like a pro. A powerful, SQL-like array filtering library for TypeScript with advanced pattern matching, MongoDB-style operators, deep object comparison, geospatial queries, and zero dependencies.

Quick Start โ€ข Why You'll Love It โ€ข Examples โ€ข Playground โ€ข Documentation


Table of Contents


The Hook

Tired of writing complex filter logic? Stop wrestling with nested Array.filter() chains and verbose conditionals. Write clean, declarative filters that read like queries.

Before:

const results = data.filter(item => item.age >= 18 && item.status === 'active' && (item.role === 'admin' || item.role === 'moderator') && item.email.endsWith('@company.com') && item.createdAt >= thirtyDaysAgo );

After:

const results = filter(data, { age: { $gte: 18 }, status: 'active', role: ['admin', 'moderator'], email: { $endsWith: '@company.com' }, createdAt: { $gte: thirtyDaysAgo } });

Same result. 70% less code. 100% more readable.


Quick Start

Install

npm install @mcabreradev/filter # or pnpm add @mcabreradev/filter # or yarn add @mcabreradev/filter

Requirements: Node.js >= 20, TypeScript 5.0+ (optional)

Your First Filter

import { filter } from '@mcabreradev/filter'; const users = [ { name: 'Alice', age: 30, city: 'Berlin', active: true }, { name: 'Bob', age: 25, city: 'London', active: false }, { name: 'Charlie', age: 35, city: 'Berlin', active: true } ]; // Simple string search const berlinUsers = filter(users, 'Berlin'); // โ†’ [{ name: 'Alice', ... }, { name: 'Charlie', ... }] // Object-based filtering const activeBerlinUsers = filter(users, { city: 'Berlin', active: true }); // โ†’ [{ name: 'Alice', ... }] // MongoDB-style operators const adults = filter(users, { age: { $gte: 18 } }); // โ†’ All users (all are 18+) // That's it! You're filtering like a pro.

๐ŸŽฎ Try it in the Playground โ†’


Why You'll Love It

๐Ÿš€ Blazing Fast

  • 530x faster with optional caching
  • 500x faster with lazy evaluation for large datasets
  • Optimized for production workloads

๐ŸŽฏ Developer Friendly

  • Intuitive API that feels natural
  • SQL-like syntax you already know
  • Full TypeScript support with intelligent autocomplete

๐Ÿ”ง Incredibly Flexible

  • Multiple filtering strategies (strings, objects, operators, predicates)
  • Works with any data structure
  • Combine approaches seamlessly

๐Ÿ“ฆ Production Ready

  • 993+ tests ensuring reliability
  • Zero dependencies (12KB gzipped)
  • Used in production by companies worldwide
  • MIT licensed

๐Ÿชถ Ultra Lightweight

  • Truly zero dependencies!
  • Tiny 12KB bundle
  • Optional Zod for validation
  • No bloat, just pure filtering power

๐Ÿ”’ Type-Safe by Default

  • Built with strict TypeScript
  • Catch errors at compile time
  • Full IntelliSense and autocomplete support

๐ŸŽจ Framework Agnostic

  • Works everywhere: React, Vue, Svelte, Angular, SolidJS, Preact
  • First-class hooks and composables included
  • SSR compatible (Next.js, Nuxt, SvelteKit)

๐Ÿ“Š Handles Big Data

  • Process millions of records efficiently
  • Lazy evaluation for memory optimization
  • Built for scale

Examples

Basic Filtering

// String matching - searches all properties filter(products, 'Laptop'); // Object matching - AND logic filter(products, { category: 'Electronics', price: { $lt: 1000 } }); // Wildcard patterns (SQL-like) filter(users, '%alice%'); // Contains 'alice' filter(users, 'Al%'); // Starts with 'Al' filter(users, '%son'); // Ends with 'son'

MongoDB-Style Operators

// Comparison operators filter(products, { price: { $gte: 100, $lte: 500 } }); // Array operators filter(products, { category: { $in: ['Electronics', 'Books'] }, tags: { $contains: 'sale' } }); // String operators filter(users, { email: { $endsWith: '@company.com' }, name: { $startsWith: 'John' } }); // Logical operators filter(products, { $and: [ { inStock: true }, { $or: [ { rating: { $gte: 4.5 } }, { price: { $lt: 50 } } ] } ] });

Array OR Syntax (Intuitive!)

// Clean array syntax - no $in needed! filter(products, { category: ['Electronics', 'Books'] }); // Equivalent to: { category: { $in: ['Electronics', 'Books'] } } // Multiple properties filter(users, { city: ['Berlin', 'Paris'], role: ['admin', 'moderator'] });

Geospatial Queries

import { filter, type GeoPoint } from '@mcabreradev/filter'; const userLocation: GeoPoint = { lat: 52.52, lng: 13.405 }; // Find restaurants within 5km filter(restaurants, { location: { $near: { center: userLocation, maxDistanceMeters: 5000 } }, rating: { $gte: 4.5 } });

Datetime Filtering

// Events in next 7 days filter(events, { date: { $upcoming: { days: 7 } } }); // Recent events (last 24 hours) filter(events, { date: { $recent: { hours: 24 } } }); // Weekday events during business hours filter(events, { date: { $dayOfWeek: [1, 2, 3, 4, 5] }, startTime: { $timeOfDay: { start: 9, end: 17 } } }); // Users who logged in recently (last 7 days) filter(users, { lastLogin: { $recent: { days: 7 } } }); // Upcoming meetings in next 2 hours filter(meetings, { startTime: { $upcoming: { hours: 2 } } }); // Weekend events only filter(events, { date: { $isWeekend: true } }); // Calculate age (users over 18) filter(users, { birthDate: { $age: { $gte: 18 } } }); // Events before a specific date filter(events, { date: { $isBefore: new Date('2025-12-31') } });

Performance Optimization

// Enable caching for repeated queries const results = filter(largeDataset, expression, { enableCache: true, orderBy: { field: 'price', direction: 'desc' }, limit: 100 }); // Lazy evaluation for large datasets import { filterFirst } from '@mcabreradev/filter'; const first10 = filterFirst(users, { premium: true }, 10);

Real-World: E-commerce Search

interface Product { id: number; name: string; price: number; category: string; brand: string; rating: number; inStock: boolean; tags: string[]; } const products: Product[] = [...]; // Find affordable, highly-rated electronics in stock const affordableElectronics = filter(products, { category: 'Electronics', price: { $lte: 1000 }, rating: { $gte: 4.5 }, inStock: true }); // Search with multiple filters const searchResults = filter(products, { name: { $contains: 'laptop' }, brand: { $in: ['Apple', 'Dell', 'HP'] }, price: { $gte: 500, $lte: 2000 } }); // Sort results const sortedProducts = filter(products, { category: 'Electronics', inStock: true }, { orderBy: [ { field: 'price', direction: 'asc' }, { field: 'rating', direction: 'desc' } ], limit: 20 });

Framework Integrations

Works seamlessly with your favorite framework:

React

import { useFilter } from '@mcabreradev/filter/react'; function UserList() { const { filtered, isFiltering } = useFilter(users, { active: true }); return <div>{filtered.map(u => <User key={u.id} {...u} />)}</div>; }

Vue

<script setup> import { useFilter } from '@mcabreradev/filter/vue'; const { filtered } = useFilter(users, { active: true }); </script>

Svelte

<script> import { useFilter } from '@mcabreradev/filter/svelte'; const { filtered } = useFilter(users, writable({ active: true })); </script>

Angular

import { FilterService } from '@mcabreradev/filter/angular'; @Component({ providers: [FilterService], template: `  @for (user of filterService.filtered(); track user.id) {  <div>{{ user.name }}</div>  }  ` }) export class UserListComponent { filterService = inject(FilterService<User>); }

SolidJS

import { useFilter } from '@mcabreradev/filter/solidjs'; function UserList() { const { filtered } = useFilter( () => users, () => ({ active: true }) ); return <For each={filtered()}>{(u) => <div>{u.name}</div>}</For>; }

Preact

import { useFilter } from '@mcabreradev/filter/preact'; function UserList() { const { filtered } = useFilter(users, { active: true }); return <div>{filtered.map(u => <div key={u.id}>{u.name}</div>)}</div>; }

Features:

  • โœ… Full TypeScript support with generics
  • โœ… Debounced search hooks/services
  • โœ… Pagination support
  • โœ… SSR compatible
  • โœ… 100% test coverage

๐Ÿ“– Complete Framework Guide โ†’


Core Features

Supported Operators

Comparison: $gt, $gte, $lt, $lte, $eq, $ne Array: $in, $nin, $contains, $size String: $startsWith, $endsWith, $contains, $regex, $match Logical: $and, $or, $not Geospatial: $near, $geoBox, $geoPolygon Datetime: $recent, $upcoming, $dayOfWeek, $timeOfDay, $age, $isWeekday, $isWeekend, $isBefore, $isAfter

TypeScript Support

Full type safety with intelligent autocomplete:

interface Product { name: string; price: number; tags: string[]; } filter<Product>(products, { price: { }, // Autocomplete: $gt, $gte, $lt, $lte, $eq, $ne name: { }, // Autocomplete: $startsWith, $endsWith, $contains, $regex tags: { } // Autocomplete: $in, $nin, $contains, $size });

Configuration Options

filter(data, expression, { caseSensitive: false, // Case-sensitive string matching maxDepth: 3, // Max depth for nested objects enableCache: true, // Enable result caching (530x faster) orderBy: 'price', // Sort results limit: 10, // Limit number of results debug: true // Visual debugging mode });

Advanced Features

Lazy Evaluation

Efficiently process large datasets with lazy evaluation:

import { filterLazy, filterFirst, filterExists, filterCount } from '@mcabreradev/filter'; // Process items on-demand const filtered = filterLazy(millionRecords, { active: true }); for (const item of filtered) { process(item); if (shouldStop) break; // Early exit } // Find first N matches const first10 = filterFirst(users, { premium: true }, 10); // Check existence without processing all items const hasAdmin = filterExists(users, { role: 'admin' }); // Count matches const activeCount = filterCount(users, { active: true });

Benefits:

  • ๐Ÿš€ 500x faster for operations that don't need all results
  • ๐Ÿ’พ 100,000x less memory for large datasets
  • โšก Early exit optimization

๐Ÿ“– Lazy Evaluation Guide โ†’

Memoization & Caching

530x faster with optional caching:

// First call - processes data const results = filter(largeDataset, { age: { $gte: 18 } }, { enableCache: true }); // Second call - returns cached result instantly const sameResults = filter(largeDataset, { age: { $gte: 18 } }, { enableCache: true });

Performance Gains:

Scenario Without Cache With Cache Speedup
Simple query (10K items) 5.3ms 0.01ms 530x
Regex pattern 12.1ms 0.02ms 605x
Complex nested 15.2ms 0.01ms 1520x

๐Ÿ“– Memoization Guide โ†’

Visual Debugging

Built-in debug mode with expression tree visualization:

filter(users, { city: 'Berlin' }, { debug: true }); // Console output: // โ”Œโ”€ Filter Debug Tree // โ”‚ Expression: {"city":"Berlin"} // โ”‚ Matched: 3/10 (30.0%) // โ”‚ Execution time: 0.42ms // โ””โ”€ โœ“ city = "Berlin"

๐Ÿ“– Debug Guide โ†’


Documentation

๐Ÿ“– Complete Guides

๐ŸŽฏ Quick Links


Performance

Filter is optimized for performance:

  • Operators use early exit strategies for fast evaluation
  • Regex patterns are compiled and cached
  • Optional caching for repeated queries (530x-1520x faster)
  • Lazy evaluation for efficient large dataset processing (500x faster)
  • Type guards for fast type checking
// โœ… Fast: Operators with early exit filter(data, { age: { $gte: 18 } }); // โœ… Fast with caching for repeated queries filter(largeData, expression, { enableCache: true }); // โœ… Fast with lazy evaluation for large datasets const result = filterFirst(millionRecords, { active: true }, 100);

Bundle Size

Import Size (gzipped) Tree-Shakeable
Full 12 KB โœ…
Core only 8.4 KB โœ…
React hooks 9.2 KB โœ…
Lazy evaluation 5.4 KB โœ…

Browser Support

Works in all modern browsers and Node.js:

  • Node.js: >= 20
  • Browsers: Chrome, Firefox, Safari, Edge (latest versions)
  • TypeScript: >= 5.0
  • Module Systems: ESM, CommonJS

Migration from v3.x

Good news: v5.x is 100% backward compatible! All v3.x code continues to work.

// โœ… All v3.x syntax still works filter(data, 'string'); filter(data, { prop: 'value' }); filter(data, (item) => true); filter(data, '%pattern%'); // โœ… New in v5.x filter(data, { age: { $gte: 18 } }); filter(data, expression, { enableCache: true });

๐Ÿ“– Migration Guide โ†’


Changelog

v5.8.3 (Current)

  • ๐Ÿ› Bug Fix: Fixed critical issue where limit option was ignored in cache key
  • โšก Performance: Replaced unbounded caches with LRU strategy to prevent memory leaks
  • ๐Ÿ”’ Stability: Improved memory management for long-running applications

v5.8.0

  • ๐ŸŽจ New Framework Integrations: Angular, SolidJS, and Preact support
  • ๐Ÿ”ข Limit Option: New limit configuration option to restrict result count
  • ๐Ÿ“Š OrderBy Option: New OrderBy configuration option to sort filtered results by field(s) in ascending or descending order
  • โœ… 993+ tests with comprehensive coverage

v5.7.0

  • ๐Ÿ…ฐ๏ธ Angular: Services and Pipes with Signals support
  • ๐Ÿ”ท SolidJS: Signal-based reactive hooks
  • โšก Preact: Lightweight hooks API

v5.6.0

  • ๐ŸŒ Geospatial Operators: Location-based filtering with $near, $geoBox, $geoPolygon
  • ๐Ÿ“… Datetime Operators: Temporal filtering with $recent, $upcoming, $dayOfWeek, $age

v5.5.0

  • ๐ŸŽจ Array OR Syntax: Intuitive array-based OR filtering
  • ๐Ÿ› Visual Debugging: Built-in debug mode with expression tree visualization
  • ๐ŸŽฎ Interactive Playground: Online playground for testing filters

๐Ÿ“– Full Changelog โ†’


Contributing

We welcome contributions! Please read our Contributing Guide for details.

Ways to Contribute:

  • Report bugs or request features via GitHub Issues
  • Submit pull requests with bug fixes or new features
  • Improve documentation
  • Share your use cases and examples

License

MIT License - see LICENSE.md for details.

Copyright (c) 2025 Miguelangel Cabrera


Support


Made with โค๏ธ for the JavaScript/TypeScript community

About

A powerful, zero-dependency filtering library that brings MongoDB-style operators, SQL wildcards, and intelligent autocomplete to TypeScript arrays. Think of it as Array.filter() on steroids! ๐Ÿ’ช

Topics

Resources

License

Contributing

Security policy

Stars

Watchers

Forks

Contributors 5