Filtering Data
Filter your data with where clauses to find exactly what you need.
Quick Navigation
- Simple Filtering
- Multiple Conditions
- Parameterized Queries
- Building Queries Conditionally
- Notes
- Related
Simple Filtering
Filter by a single condition:
import { DataStore } from "@routier/datastore";
import { s } from "@routier/core/schema";
import { MemoryPlugin } from "@routier/memory-plugin";
const productSchema = s.define("products", {
_id: s.string().key().identity(),
name: s.string(),
price: s.number(),
category: s.string(),
inStock: s.boolean(),
tags: s.string("computer", "accessory").array(),
createdDate: s.date().default(() => new Date())
}).compile();
class AppDataStore extends DataStore {
products = this.collection(productSchema).create();
constructor() {
super(new MemoryPlugin("app"));
}
}
const dataStore = new AppDataStore();
// Simple filtering
const expensiveProducts = await dataStore.products
.where(p => p.price > 100)
.toArrayAsync();Multiple Conditions
Chain multiple where clauses for AND logic:
import { DataStore } from "@routier/datastore";
import { s } from "@routier/core/schema";
import { MemoryPlugin } from "@routier/memory-plugin";
const productSchema = s.define("products", {
_id: s.string().key().identity(),
name: s.string(),
price: s.number(),
category: s.string(),
inStock: s.boolean(),
tags: s.string("computer", "accessory").array(),
createdDate: s.date().default(() => new Date())
}).compile();
class AppDataStore extends DataStore {
products = this.collection(productSchema).create();
constructor() {
super(new MemoryPlugin("app"));
}
}
const dataStore = new AppDataStore();
// Multiple where clauses (AND logic)
const expensiveElectronics = await dataStore.products
.where(p => p.price > 100)
.where(p => p.category === "electronics")
.toArrayAsync();Parameterized Queries
Use parameters for dynamic filtering with variables. This is required when you want to use variables in your query predicates.
Why Parameterized Queries?
When you need to use variables in your query, you must use parameterized queries. Direct variable usage in predicates will still work, but Routier will fall back to selecting all records because it cannot evaluate the variable values:
// ⚠️ This works but selects ALL records first, then filters in memory - less efficient
const minPrice = 100;
const maxPrice = 500;
const products = await dataStore.products
.where((p) => p.price >= minPrice && p.price <= maxPrice) // Selects all, filters in memory
.toArrayAsync();
Result: You’ll get the correct filtered results, but Routier will first load all records into memory, then apply the filter. This is less efficient than database-level filtering.
How Parameterized Queries Work
Pass variables through a parameters object:
import { DataStore } from "@routier/datastore";
import { s } from "@routier/core/schema";
import { MemoryPlugin } from "@routier/memory-plugin";
const productSchema = s.define("products", {
_id: s.string().key().identity(),
name: s.string(),
price: s.number(),
category: s.string(),
inStock: s.boolean(),
tags: s.string("computer", "accessory").array(),
createdDate: s.date().default(() => new Date())
}).compile();
class AppDataStore extends DataStore {
products = this.collection(productSchema).create();
constructor() {
super(new MemoryPlugin("app"));
}
}
const dataStore = new AppDataStore();
// Parameterized queries
const minPrice = 50;
const maxPrice = 200;
const filteredProducts = await dataStore.products
.where(([p, params]) => p.price >= params.minPrice && p.price <= params.maxPrice,
{ minPrice, maxPrice })
.toArrayAsync();Common Use Cases
Dynamic filtering based on user input:
const searchTerm = "laptop";
const category = "electronics";
const minPrice = 100;
const results = await dataStore.products
.where(
([p, params]) =>
p.name.toLowerCase().includes(params.searchTerm.toLowerCase()) &&
p.category === params.category &&
p.price >= params.minPrice,
{ searchTerm, category, minPrice }
)
.toArrayAsync();
Pagination with dynamic page size:
const page = 2;
const pageSize = 20;
const offset = (page - 1) * pageSize;
const products = await dataStore.products
.where(([p, params]) => p.inStock === true, {})
.skip(offset)
.take(pageSize)
.toArrayAsync();
Building Queries Conditionally
You can build queries dynamically by assigning query results back to a variable and chaining additional operations conditionally:
import { DataStore } from "@routier/datastore";
import { s } from "@routier/core/schema";
import { MemoryPlugin } from "@routier/memory-plugin";
import { InferType } from "@routier/core/schema";
const productSchema = s.define("products", {
id: s.string().key().identity(),
name: s.string(),
category: s.string(),
price: s.number(),
inStock: s.boolean(),
}).compile();
type Product = InferType<typeof productSchema>;
class AppDataStore extends DataStore {
products = this.collection(productSchema).create();
constructor() {
super(new MemoryPlugin("app"));
}
}
const dataStore = new AppDataStore();
// Building a query dynamically based on logic
// In this example, we build a query by conditionally adding filters
const minPrice = 100;
const categoryFilter = "electronics";
// Convert collection to QueryableAsync for building queries dynamically
let query = dataStore.products.toQueryable();
// Build query conditionally - only add filters that apply
if (categoryFilter) {
query = query.where(([p, params]) =>
p.category === params.categoryFilter,
{ categoryFilter }
);
}
if (minPrice > 0) {
query = query.where(([p, params]) =>
p.price >= params.minPrice,
{ minPrice }
);
}
// Execute the built query
const results = await query.toArrayAsync();
// Pattern: Building queries with arrays using includes()
// When filtering by multiple ID values from an array
const productIds = ["prod-1", "prod-2", "prod-3"];
const productsByIds = await dataStore.products
.where(([p, params]) =>
params.ids.includes(p.id),
{ ids: productIds }
)
.toArrayAsync();Key Pattern
Start with a base query and conditionally add filters:
// Start with base collection
let query = dataStore.products;
// Conditionally add filters based on logic
// Always use parameterized queries when using variables
if (shouldFilterByCategory) {
query = query.where(([p, params]) => p.category === params.category, {
category: "electronics",
});
}
if (minPrice > 0) {
query = query.where(([p, params]) => p.price >= params.minPrice, {
minPrice,
});
}
// Execute after building
const results = await query.toArrayAsync();
Filtering by Arrays
Use parameterized queries with includes() to filter by multiple values:
const productIds = ["prod-1", "prod-2", "prod-3"];
const products = await dataStore.products
.where(([p, params]) => params.ids.includes(p.id), { ids: productIds })
.toArrayAsync();
This pattern is especially useful when building queries in loops or based on conditional logic, as seen in Routier’s internal view computation system.
Notes
wheresupports either a simple predicate(item) => booleanor a parameterized predicate(item, params) => booleanwith a params object- Use parameterized queries when you need variables - non-parameterized queries with variables will select all records and filter in memory (less efficient)
- Multiple
whereclauses are combined with AND logic - For OR logic, use a single
wherewith||operators inside the predicate