Object Query Builder
π§© A powerful, type-safe SQL-like query builder for JavaScript objects
Β· English Β· Korean
β¨ Features
- π¨ Fluent API - Chainable methods for readable queries
- π― SQL-like Syntax - Familiar query syntax for filtering, sorting, and joining
- π§ Extensible - Easy to add custom functionality
- π Type-Safe - Full TypeScript support with generics
- β‘ High Performance - Optimized algorithms (O(n) joins with Map)
- π¦ Zero Dependencies - Pure TypeScript, no external dependencies
- π Modern Build - Dual CJS/ESM support with tsup
π Installation
npm install object-querybuilder
yarn add object-querybuilder
pnpm add object-querybuilderπ Quick Start
TypeScript
import QueryBuilder from 'object-querybuilder';
interface User {
name: string;
age: number;
gender: string;
}
const users: User[] = [
{ name: 'Lucy', age: 23, gender: 'woman' },
{ name: 'Emma', age: 31, gender: 'woman' },
{ name: 'Daniel', age: 18, gender: 'man' },
{ name: 'Olivia', age: 42, gender: 'woman' },
{ name: 'Alex', age: 33, gender: 'man' }
];
const result = QueryBuilder.create<User>()
.select(['name', 'age'])
.from(users)
.where('age', '>', 25)
.where('gender', '=', 'woman')
.orderBy('age', 'desc')
.run();
console.log(result);
// Output: [
// { name: 'Olivia', age: 42 },
// { name: 'Emma', age: 31 }
// ]JavaScript (CommonJS)
const QueryBuilder = require('object-querybuilder').default;
const users = [
{ name: 'Lucy', age: 23, gender: 'woman' },
{ name: 'Emma', age: 31, gender: 'woman' }
];
const result = QueryBuilder.create()
.select(['*'])
.from(users)
.where('age', '>', 25)
.run();JavaScript (ESM)
import QueryBuilder from 'object-querybuilder';
const result = QueryBuilder.create()
.select(['name', 'age'])
.from(users)
.orderBy('age', 'asc')
.limit(5)
.run();π API Reference
Core Query Methods
| Method | Description | Example |
|---|---|---|
select(fields) |
Specify fields to return (['*'] for all) |
.select(['name', 'age']) |
from(data) |
Set data source (array or single object) | .from(users) |
where(key, op, value) |
Filter by condition | .where('age', '>', 25) |
whereIn(key, values) |
Filter by array inclusion | .whereIn('status', ['active', 'pending']) |
whereNotIn(key, values) |
Filter by array exclusion | .whereNotIn('role', ['admin']) |
orderBy(key, order) |
Sort results (asc/desc) | .orderBy('age', 'desc') |
orderByMultiple(criteria) |
Sort by multiple fields | .orderByMultiple([{key: 'dept', order: 'asc'}]) |
limit(count) |
Limit number of results | .limit(10) |
offset(count) |
Skip number of results | .offset(20) |
distinct() |
Remove duplicates | .distinct() |
run() |
Execute query and return results | .run() |
Join Methods
| Method | Description | Example |
|---|---|---|
join(data, key) |
Inner join on common key | .join(addresses, 'userId') |
leftJoin(data, key) |
Left outer join | .leftJoin(addresses, 'userId') |
Aggregation Methods
| Method | Description | Example |
|---|---|---|
count() |
Count results | .count() |
aggregate(func, key) |
Apply function (sum, avg, min, max) | .aggregate('sum', 'salary') |
groupBy(key) |
Group results by field | .groupBy('department') |
first() |
Get first result | .first() |
last() |
Get last result | .last() |
Utility Methods
| Method | Description | Example |
|---|---|---|
clone() |
Create independent copy | .clone() |
Supported Operators
| Operator | Description | Example |
|---|---|---|
> |
Greater than | .where('age', '>', 25) |
< |
Less than | .where('price', '<', 100) |
>= |
Greater than or equal | .where('score', '>=', 90) |
<= |
Less than or equal | .where('stock', '<=', 10) |
= |
Equal | .where('status', '=', 'active') |
!= |
Not equal | .where('type', '!=', 'draft') |
like |
Pattern matching (%, _) | .where('email', 'like', '%@gmail.com') |
π‘ Examples
Basic Filtering
// Single condition
QueryBuilder.create()
.select(['*'])
.from(products)
.where('price', '<', 100)
.run();
// Multiple conditions (chained)
QueryBuilder.create()
.select(['*'])
.from(users)
.where('age', '>=', 18)
.where('status', '=', 'active')
.whereIn('role', ['user', 'moderator'])
.run();Pattern Matching
// Find emails from Gmail
QueryBuilder.create()
.from(users)
.where('email', 'like', '%@gmail.com')
.run();
// Find names starting with 'A'
QueryBuilder.create()
.from(users)
.where('name', 'like', 'A%')
.run();
// Find names containing 'son'
QueryBuilder.create()
.from(users)
.where('name', 'like', '%son%')
.run();Joining Data
const users = [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' }
];
const orders = [
{ userId: 1, product: 'Laptop', amount: 1200 },
{ userId: 1, product: 'Mouse', amount: 25 },
{ userId: 2, product: 'Keyboard', amount: 75 }
];
// Inner join (only matching records)
const result = QueryBuilder.create()
.from(users)
.join(orders, 'userId')
.run();
// Left join (all users, even without orders)
const result = QueryBuilder.create()
.from(users)
.leftJoin(orders, 'userId')
.run();Pagination
const PAGE_SIZE = 10;
const currentPage = 3;
const result = QueryBuilder.create()
.select(['*'])
.from(items)
.orderBy('createdAt', 'desc')
.limit(PAGE_SIZE)
.offset((currentPage - 1) * PAGE_SIZE)
.run();Aggregation & Analytics
const sales = [
{ product: 'Laptop', price: 1200, quantity: 5 },
{ product: 'Mouse', price: 25, quantity: 50 },
{ product: 'Keyboard', price: 75, quantity: 20 }
];
// Total revenue
const total = QueryBuilder.create()
.from(sales)
.aggregate('sum', 'price');
// Result: 1300
// Average price
const avg = QueryBuilder.create()
.from(sales)
.aggregate('avg', 'price');
// Result: 433.33
// Most expensive item
const max = QueryBuilder.create()
.from(sales)
.aggregate('max', 'price');
// Result: 1200
// Group by and count
const grouped = QueryBuilder.create()
.from(orders)
.groupBy('status');
// Result: { 'pending': [...], 'completed': [...], 'cancelled': [...] }Sorting
// Single field
QueryBuilder.create()
.from(products)
.orderBy('price', 'desc')
.run();
// Multiple fields
QueryBuilder.create()
.from(employees)
.orderByMultiple([
{ key: 'department', order: 'asc' },
{ key: 'salary', order: 'desc' },
{ key: 'name', order: 'asc' }
])
.run();Advanced Use Cases
// Find top 5 most expensive products in Electronics
QueryBuilder.create()
.select(['name', 'price', 'rating'])
.from(products)
.where('category', '=', 'Electronics')
.where('inStock', '=', true)
.orderBy('price', 'desc')
.limit(5)
.run();
// Get unique active users who made purchases
QueryBuilder.create()
.select(['userId', 'username'])
.from(transactions)
.where('status', '=', 'completed')
.whereIn('userId', activeUserIds)
.distinct()
.run();
// Reusable query with cloning
const baseQuery = QueryBuilder.create()
.from(users)
.where('status', '=', 'active');
const adults = baseQuery.clone()
.where('age', '>=', 18)
.run();
const minors = baseQuery.clone()
.where('age', '<', 18)
.run();π― Use Cases
- Frontend Data Filtering - Filter API responses in browser
- Testing - Mock database queries without actual DB
- Data Processing - Transform and analyze in-memory data
- Prototyping - Quick data manipulation without backend
- Report Generation - Aggregate and summarize data
- ETL Operations - Extract, transform, load data pipelines
π€ Contributing
Contributions are always welcome! Please feel free to open an issue or submit a pull request.
π³ License
Made with β€οΈ by AGUMON π¦
On this page
Languages
TypeScript98.4%JavaScript1.6%
Contributors
MIT License
Created August 8, 2020
Updated October 22, 2025