Skip to content

Commit c730549

Browse files
Copilothotlong
andcommitted
Update best-practices and formulas docs with new query syntax
Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
1 parent eb233be commit c730549

File tree

2 files changed

+54
-57
lines changed

2 files changed

+54
-57
lines changed

content/docs/data-access/best-practices.mdx

Lines changed: 30 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -40,11 +40,10 @@ The **JSON-DSL** is ObjectQL's core query language - a structured JSON represent
4040
```typescript
4141
const tasks = await app.object('task').find({
4242
fields: ['name', 'status', 'due_date'],
43-
filters: [
44-
['status', '=', 'active'],
45-
'and',
46-
['priority', '>=', 3]
47-
],
43+
filters: {
44+
status: 'active',
45+
priority: { $gte: 3 }
46+
},
4847
sort: [['due_date', 'asc']],
4948
skip: 0,
5049
limit: 20
@@ -59,7 +58,7 @@ const tasks = await app.object('task').find({
5958
```typescript
6059
// Returns ALL fields (inefficient)
6160
await app.object('user').find({
62-
filters: [['status', '=', 'active']]
61+
filters: { status: 'active' }
6362
});
6463
```
6564

@@ -68,7 +67,7 @@ await app.object('user').find({
6867
// Returns only needed fields (efficient)
6968
await app.object('user').find({
7069
fields: ['id', 'name', 'email'],
71-
filters: [['status', '=', 'active']]
70+
filters: { status: 'active' }
7271
});
7372
```
7473

@@ -79,17 +78,16 @@ await app.object('user').find({
7978
**Bad:**
8079
```typescript
8180
// Filters on non-indexed field
82-
filters: [['description', 'contains', 'urgent']]
81+
filters: { description: { $contains: 'urgent' } }
8382
```
8483

8584
**Good:**
8685
```typescript
8786
// Filters on indexed field first, then post-filter if needed
88-
filters: [
89-
['status', '=', 'open'], // Indexed
90-
'and',
91-
['priority', '=', 'high'] // Indexed
92-
]
87+
filters: {
88+
status: 'open', // Indexed
89+
priority: 'high' // Indexed
90+
}
9391
```
9492

9593
**Impact:** Can improve query speed by 10-100x depending on dataset size.
@@ -100,15 +98,15 @@ filters: [
10098
```typescript
10199
// Returns all records (dangerous)
102100
await app.object('order').find({
103-
filters: [['year', '=', 2024]]
101+
filters: { year: 2024 }
104102
});
105103
```
106104

107105
**Good:**
108106
```typescript
109107
// Paginated results (safe and fast)
110108
await app.object('order').find({
111-
filters: [['year', '=', 2024]],
109+
filters: { year: 2024 },
112110
limit: 50,
113111
skip: page * 50,
114112
sort: [['created_at', 'desc']]
@@ -431,7 +429,7 @@ const tasksWithAssignee = await Promise.all(
431429
const tasks = await taskRepo.find();
432430
const userIds = tasks.map(t => t.assignee_id);
433431
const users = await userRepo.find({
434-
filters: [['id', 'in', userIds]]
432+
filters: { id: { $in: userIds } }
435433
});
436434
const userMap = new Map(users.map(u => [u.id, u]));
437435
const tasksWithAssigneeBatched = tasks.map((task) => ({
@@ -516,7 +514,7 @@ query Dashboard {
516514
// Hook: Automatically assign to least-busy team member
517515
async function autoAssign(task: any) {
518516
const members = await app.object('user').aggregate({
519-
filters: [['team_id', '=', task.team_id]],
517+
filters: { team_id: task.team_id },
520518
groupBy: ['id', 'name'],
521519
aggregate: [
522520
{ func: 'count', field: 'tasks.id', alias: 'task_count' }
@@ -581,7 +579,7 @@ AND priority = 'high' AND invalid_function(status);
581579
**Bad (Application-level aggregation):**
582580
```typescript
583581
const orders = await app.object('order').find({
584-
filters: [['status', '=', 'paid']]
582+
filters: { status: 'paid' }
585583
});
586584

587585
// Slow: Iterating in application code
@@ -594,7 +592,7 @@ for (const order of orders) {
594592
**Good (Database-level aggregation):**
595593
```typescript
596594
const stats = await app.object('order').aggregate({
597-
filters: [['status', '=', 'paid']],
595+
filters: { status: 'paid' },
598596
groupBy: ['customer_id'],
599597
aggregate: [
600598
{ func: 'sum', field: 'amount', alias: 'total_revenue' },
@@ -620,7 +618,7 @@ const uniqueCustomers = [...new Set(orders.map(o => o.customer_id))];
620618
**Good:**
621619
```typescript
622620
const uniqueCustomers = await app.object('order').distinct('customer_id', {
623-
filters: [['year', '=', 2024]]
621+
filters: { year: 2024 }
624622
});
625623
```
626624

@@ -661,18 +659,19 @@ indexes:
661659
662660
**Bad (OR requires multiple index scans):**
663661
```typescript
664-
filters: [
665-
['status', '=', 'pending'],
666-
'or',
667-
['status', '=', 'active']
668-
]
662+
filters: {
663+
$or: [
664+
{ status: 'pending' },
665+
{ status: 'active' }
666+
]
667+
}
669668
```
670669

671670
**Good (IN uses single index scan):**
672671
```typescript
673-
filters: [
674-
['status', 'in', ['pending', 'active']]
675-
]
672+
filters: {
673+
status: { $in: ['pending', 'active'] }
674+
}
676675
```
677676

678677
**Impact:** 2-5x faster for large tables.
@@ -693,7 +692,7 @@ await app.object('order').find({
693692
**Good (Cursor pagination using last ID):**
694693
```typescript
695694
await app.object('order').find({
696-
filters: [['id', '>', lastSeenId]],
695+
filters: { id: { $gt: lastSeenId } },
697696
limit: 50,
698697
sort: [['id', 'asc']]
699698
});
@@ -754,7 +753,7 @@ GET /api/data/tasks?status=active&limit=20
754753
**After:**
755754
```typescript
756755
await app.object('task').find({
757-
filters: [['status', '=', 'active']],
756+
filters: { status: 'active' },
758757
limit: 20
759758
});
760759
```
@@ -764,7 +763,7 @@ await app.object('task').find({
764763
**Before:**
765764
```typescript
766765
const tasks = await app.object('task').find({
767-
filters: [['status', '=', 'active']],
766+
filters: { status: 'active' },
768767
expand: {
769768
assignee: { fields: ['name', 'email'] }
770769
}

content/docs/logic/formulas.mdx

Lines changed: 24 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -385,10 +385,10 @@ rules:
385385
validator: |
386386
async function validate(record, context) {
387387
const customer = await context.api.findOne('customers', record.customer_id);
388-
const totalOrders = await context.api.sum('orders', 'amount', [
389-
['customer_id', '=', record.customer_id],
390-
['status', 'in', ['pending', 'processing']]
391-
]);
388+
const totalOrders = await context.api.sum('orders', 'amount', {
389+
customer_id: record.customer_id,
390+
status: { $in: ['pending', 'processing'] }
391+
});
392392
393393
return (totalOrders + record.amount) <= customer.credit_limit;
394394
}
@@ -546,33 +546,31 @@ condition:
546546
Used in query language for filtering records:
547547

548548
```javascript
549-
// Basic filter - [field, operator, value]
550-
["status", "=", "active"]
549+
// Basic filter - object with implicit equality
550+
{ status: 'active' }
551551
552-
// Multiple filters with AND
553-
[
554-
["status", "=", "active"],
555-
"and",
556-
["amount", ">", 1000]
557-
]
552+
// Multiple filters with AND (implicit)
553+
{
554+
status: 'active',
555+
amount: { $gt: 1000 }
556+
}
558557
559558
// Multiple filters with OR
560-
[
561-
["priority", "=", "high"],
562-
"or",
563-
["amount", ">", 50000]
564-
]
559+
{
560+
$or: [
561+
{ priority: 'high' },
562+
{ amount: { $gt: 50000 } }
563+
]
564+
}
565565
566566
// Complex nested conditions
567-
[
568-
["status", "=", "active"],
569-
"and",
570-
[
571-
["priority", "=", "high"],
572-
"or",
573-
["amount", ">", 10000]
567+
{
568+
status: 'active',
569+
$or: [
570+
{ priority: 'high' },
571+
{ amount: { $gt: 10000 } }
574572
]
575-
]
573+
}
576574
```
577575

578576
## Best Practices
@@ -665,7 +663,7 @@ rules:
665663
async function validateBatch(records, context) {
666664
const skus = records.map(r => r.sku);
667665
const inventory = await context.api.find('inventory', {
668-
filters: [['sku', 'in', skus]]
666+
filters: { sku: { $in: skus } }
669667
});
670668
671669
return records.map(record => {

0 commit comments

Comments
 (0)