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
- @mcabreradev/filter
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.
npm install @mcabreradev/filter
# or
pnpm add @mcabreradev/filter
# or
yarn add @mcabreradev/filterRequirements: Node.js >= 20, TypeScript 5.0+ (optional)
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.- 530x faster with optional caching
- 500x faster with lazy evaluation for large datasets
- Optimized for production workloads
- Intuitive API that feels natural
- SQL-like syntax you already know
- Full TypeScript support with intelligent autocomplete
- Multiple filtering strategies (strings, objects, operators, predicates)
- Works with any data structure
- Combine approaches seamlessly
- 993+ tests ensuring reliability
- Zero dependencies (12KB gzipped)
- Used in production by companies worldwide
- MIT licensed
- Truly zero dependencies!
- Tiny 12KB bundle
- Optional Zod for validation
- No bloat, just pure filtering power
- Built with strict TypeScript
- Catch errors at compile time
- Full IntelliSense and autocomplete support
- Works everywhere: React, Vue, Svelte, Angular, SolidJS, Preact
- First-class hooks and composables included
- SSR compatible (Next.js, Nuxt, SvelteKit)
- Process millions of records efficiently
- Lazy evaluation for memory optimization
- Built for scale
// 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'// 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 } }
]
}
]
});// 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']
});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 }
});// 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') }
});// 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);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
});Works seamlessly with your favorite framework:
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>;
}<script setup>
import { useFilter } from '@mcabreradev/filter/vue';
const { filtered } = useFilter(users, { active: true });
</script><script>
import { useFilter } from '@mcabreradev/filter/svelte';
const { filtered } = useFilter(users, writable({ active: true }));
</script>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>);
}import { useFilter } from '@mcabreradev/filter/solidjs';
function UserList() {
const { filtered } = useFilter(
() => users,
() => ({ active: true })
);
return <For each={filtered()}>{(u) => <div>{u.name}</div>}</For>;
}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
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
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
});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
});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
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 |
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"- Getting Started - Installation and first steps
- All Operators - Complete operator reference
- Geospatial Queries - Location-based filtering
- Datetime Operators - Temporal filtering
- Framework Integrations - React, Vue, Svelte, Angular, SolidJS, Preact
- Lazy Evaluation - Efficient large dataset processing
- Memoization & Caching - Performance optimization
- Visual Debugging - Debug mode and tree visualization
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);| Import | Size (gzipped) | Tree-Shakeable |
|---|---|---|
| Full | 12 KB | ✅ |
| Core only | 8.4 KB | ✅ |
| React hooks | 9.2 KB | ✅ |
| Lazy evaluation | 5.4 KB | ✅ |
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
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 });- 🎨 New Framework Integrations: Angular, SolidJS, and Preact support
- 🔢 Limit Option: New
limitconfiguration option to restrict result count - 📊 OrderBy Option: New
OrderByconfiguration option to sort filtered results by field(s) in ascending or descending order - ✅ 993+ tests with comprehensive coverage
🅰️ Angular: Services and Pipes with Signals support- 🔷 SolidJS: Signal-based reactive hooks
- ⚡ Preact: Lightweight hooks API
- 🌍 Geospatial Operators: Location-based filtering with $near, $geoBox, $geoPolygon
- 📅 Datetime Operators: Temporal filtering with $recent, $upcoming, $dayOfWeek, $age
- 🎨 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
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
MIT License - see LICENSE.md for details.
Copyright (c) 2025 Miguelangel Cabrera
Made with ❤️ for the JavaScript/TypeScript community