
Product
Introducing Webhook Events for Alert Changes
Add real-time Socket webhook events to your workflows to automatically receive software supply chain alert changes in real time.
@mcabreradev/filter
Advanced tools
A powerful, SQL-like array filtering library for TypeScript and JavaScript with advanced pattern matching, MongoDB-style operators, deep object comparison, and zero dependencies
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
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/filter
Requirements: 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.
// 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:
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:
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"
Filter is optimized for performance:
// ✅ 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:
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 });
limit configuration option to restrict result countOrderBy configuration option to sort filtered results by field(s) in ascending or descending orderWe welcome contributions! Please read our Contributing Guide for details.
Ways to Contribute:
MIT License - see LICENSE.md for details.
Copyright (c) 2025 Miguelangel Cabrera
Made with ❤️ for the JavaScript/TypeScript community
FAQs
A powerful, SQL-like array filtering library for TypeScript and JavaScript with advanced pattern matching, MongoDB-style operators, deep object comparison, and zero dependencies
The npm package @mcabreradev/filter receives a total of 48 weekly downloads. As such, @mcabreradev/filter popularity was classified as not popular.
We found that @mcabreradev/filter demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Product
Add real-time Socket webhook events to your workflows to automatically receive software supply chain alert changes in real time.

Security News
ENISA has become a CVE Program Root, giving the EU a central authority for coordinating vulnerability reporting, disclosure, and cross-border response.

Product
Socket now scans OpenVSX extensions, giving teams early detection of risky behaviors, hidden capabilities, and supply chain threats in developer tools.