Real-Time Filtering Tutorial
Build dynamic filtering into your application.
What You'll Build
A product catalog with real-time filtering by category, price, and availability.
Step 1: Create Product Catalog
import { InMemoryGraphFactory } from 'grafio';
import { CypherEngine } from 'grafio/cypher';
const factory = new InMemoryGraphFactory();
const graph = factory.forGraph('default');
const engine = new CypherEngine(graph);
// Build graph
await engine.execute(`
CREATE (electronics:Category {name: 'Electronics'}),
(clothing:Category {name: 'Clothing'}),
(laptop:Product {name: 'Laptop', price: 999, inStock: true}),
(phone:Product {name: 'Phone', price: 699, inStock: true}),
(headphones:Product {name: 'Headphones', price: 149, inStock: false}),
(tshirt:Product {name: 'T-Shirt', price: 29, inStock: true}),
(jeans:Product {name: 'Jeans', price: 79, inStock: true})
`);
await engine.execute(`
MATCH (e:Category {name: 'Electronics'}), (laptop:Product {name: 'Laptop'})
MATCH (p:Product {name: 'Phone'}), (h:Product {name: 'Headphones'})
MATCH (c:Category {name: 'Clothing'}), (t:Product {name: 'T-Shirt'}), (j:Product {name: 'Jeans'})
CREATE (e)-[:CONTAINS]->(laptop)
CREATE (e)-[:CONTAINS]->(p)
CREATE (e)-[:CONTAINS]->(h)
CREATE (c)-[:CONTAINS]->(t)
CREATE (c)-[:CONTAINS]->(j)
`);
Step 2: Filter by Single Condition
Filter by Category
const electronicsProducts = await engine.query(`
MATCH (c:Category {name: 'Electronics'})-[:CONTAINS]->(p:Product)
RETURN p.name, p.price
`);
Filter by Price
const affordableProducts = await engine.query(`
MATCH (p:Product)
WHERE p.price < 100
RETURN p.name, p.price
`);
Step 3: Filter by Multiple Conditions
AND Conditions
const cheapInStock = await engine.query(`
MATCH (p:Product)
WHERE p.price < 100 AND p.inStock = true
RETURN p.name, p.price
`);
OR Conditions
const premiumOrInStock = await engine.query(`
MATCH (p:Product)
WHERE p.price > 500 OR p.inStock = true
RETURN p.name, p.price, p.inStock
`);
Complex Filters
const electronicsUnder500 = await engine.query(`
MATCH (c:Category {name: 'Electronics'})-[:CONTAINS]->(p:Product)
WHERE p.price < 500 AND p.inStock = true
RETURN p.name, p.price
ORDER BY p.price
`);
Step 4: String Filters
CONTAINS
const nameSearch = await engine.query(`
MATCH (p:Product)
WHERE p.name CONTAINS 'phone'
RETURN p.name
`);
STARTS WITH / ENDS WITH
const tProducts = await engine.query(`
MATCH (p:Product)
WHERE p.name STARTS WITH 'T'
RETURN p.name
`);
Step 5: List Filters (IN / NOT IN)
const specificProducts = await engine.query(`
MATCH (p:Product)
WHERE p.name IN ['Laptop', 'Jeans']
RETURN p.name
`);
NOT IN
const excludeCategories = await engine.query(`
MATCH (p:Product)
WHERE p.name NOT IN ['T-Shirt']
RETURN p.name
`);
Step 6: NULL Handling
// Products without discount
const noDiscount = await engine.query(`
MATCH (p:Product)
WHERE p.discount IS NULL
RETURN p.name
`);
// Products with discount
const withDiscount = await engine.query(`
MATCH (p:Product)
WHERE p.discount IS NOT NULL
RETURN p.name
`);
Step 7: Pagination
// First page
const page1 = await engine.query(`
MATCH (p:Product)
RETURN p.name, p.price
ORDER BY p.price
SKIP 0 LIMIT 3
`);
// Second page
const page2 = await engine.query(`
MATCH (p:Product)
RETURN p.name, p.price
ORDER BY p.price
SKIP 3 LIMIT 3
`);
Step 8: Aggregation with Filters
const stats = await engine.query(`
MATCH (p:Product)
WHERE p.inStock = true
RETURN COUNT(*) AS total,
AVG(p.price) AS avgPrice,
MIN(p.price) AS minPrice,
MAX(p.price) AS maxPrice
`);
Group by Category
const byCategory = await engine.query(`
MATCH (c:Category)-[:CONTAINS]->(p:Product)
WHERE p.inStock = true
RETURN c.name AS category,
COUNT(*) AS count,
AVG(p.price) AS avgPrice
ORDER BY avgPrice DESC
`);
Complete Filter Function
async function filterProducts(filters: {
category?: string;
minPrice?: number;
maxPrice?: number;
inStock?: boolean;
search?: string;
page?: number;
pageSize?: number;
}) {
let query = `
MATCH (c:Category)-[:CONTAINS]->(p:Product)
WHERE 1=1
`;
if (filters.category) {
query += ` AND c.name = '${filters.category}'`;
}
if (filters.minPrice !== undefined) {
query += ` AND p.price >= ${filters.minPrice}`;
}
if (filters.maxPrice !== undefined) {
query += ` AND p.price <= ${filters.maxPrice}`;
}
if (filters.inStock !== undefined) {
query += ` AND p.inStock = ${filters.inStock}`;
}
if (filters.search) {
query += ` AND p.name CONTAINS '${filters.search}'`;
}
query += ` RETURN p.name, p.price, p.inStock ORDER BY p.price`;
if (filters.page !== undefined && filters.pageSize !== undefined) {
query += ` SKIP ${filters.page * filters.pageSize} LIMIT ${filters.pageSize}`;
}
return engine.query(query);
}
// Usage
const results = await filterProducts({
category: 'Electronics',
maxPrice: 500,
inStock: true,
page: 0,
pageSize: 10
});
Next Steps
- Filtering Guide — full filtering reference
- Cypher Language Guide — WHERE clause details
- Core Concepts Guide — graph data model