Routier queries are fluent and can only be performed through a collection. Build your query by chaining operations and finish with a terminal method to execute.
// Get all productsconstallProducts=awaitctx.products.toArrayAsync();
Getting Single Items
>
1
2
3
4
5
// Get first product (throws if none exist)constfirstProduct=awaitctx.products.firstAsync();// Get first product or undefined if none existconstfirstOrUndefined=awaitctx.products.firstOrUndefinedAsync();
Checking Existence
>
1
2
3
4
5
// Check if any products existconsthasProducts=awaitctx.products.someAsync();// Check if all products are in stockconstallInStock=awaitctx.products.everyAsync((p)=>p.inStock);
Counting Items
>
1
2
3
4
5
6
7
// Count total productsconsttotalCount=awaitctx.products.countAsync();// Count products in specific categoryconstelectronicsCount=awaitctx.products.where((p)=>p.category==="electronics").countAsync();
// Sort by price (ascending)constproductsByPrice=awaitctx.products.sort((p)=>p.price).toArrayAsync();// Sort by price (descending)constexpensiveFirst=awaitctx.products.orderByDescending((p)=>p.price).toArrayAsync();// Multiple sort criteriaconstsortedProducts=awaitctx.products.sort((p)=>p.category).sort((p)=>p.name).toArrayAsync();
Field Selection and Transformation
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Select specific fields to reduce data transferconstproductSummaries=awaitctx.products.map((p)=>({id:p.id,name:p.name,price:p.price,})).toArrayAsync();// Create computed fields on-the-flyconstproductsWithTax=awaitctx.products.map((p)=>({id:p.id,name:p.name,price:p.price,priceWithTax:p.price*1.1,})).toArrayAsync();
Pagination
>
1
2
3
4
5
6
7
8
9
10
11
12
13
// Get first 10 productsconstfirstPage=awaitctx.products.take(10).toArrayAsync();// Get second page (skip first 10, take next 10)constsecondPage=awaitctx.products.skip(10).take(10).toArrayAsync();// Pagination helperconstpageSize=10;constpageNumber=2;// 0-basedconstpage=awaitctx.products.skip(pageSize*pageNumber).take(pageSize).toArrayAsync();
Aggregation Operations
>
1
2
3
4
5
6
7
8
9
10
11
// Sum prices of in-stock productsconsttotalValue=awaitctx.products.where((p)=>p.inStock===true).sumAsync((p)=>p.price);// Get minimum and maximum pricesconstminPrice=awaitctx.products.minAsync((p)=>p.price);constmaxPrice=awaitctx.products.maxAsync((p)=>p.price);// Get distinct categoriesconstcategories=awaitctx.products.map((p)=>p.category).distinctAsync();
Complex Queries
>
1
2
3
4
5
6
7
8
9
10
11
12
// Complex query with multiple operationsconsttopExpensiveElectronics=awaitctx.products.where((p)=>p.category==="electronics").where((p)=>p.inStock===true).orderByDescending((p)=>p.price).take(5).map((p)=>({name:p.name,price:p.price,priceWithTax:p.price*1.1,})).toArrayAsync();
Key Concepts
Query Execution
Lazy evaluation: Queries don’t execute until you call a terminal method
Chaining: You can chain multiple operations together
Collection-based: All queries must start with a collection
Performance Tips
Database filters first: Apply where clauses on database fields before computed fields
Limit results: Use take() to limit large result sets
Efficient pagination: Use skip() and take() for pagination
Computed Properties
When filtering on computed properties (not stored in database), the filter runs in memory:
>
1
2
3
4
5
6
7
8
9
10
11
// Good: Database-backed filter firstconstexpensiveElectronics=awaitctx.products.where((p)=>p.category==="electronics")// Database filter.where((p)=>p.isExpensive===true)// Computed filter.toArrayAsync();// Less efficient: Computed filter firstconstallExpensive=awaitctx.products.where((p)=>p.isExpensive===true)// Loads all records.where((p)=>p.category==="electronics")// Then filters.toArrayAsync();