76 lines
2.6 KiB
Markdown
76 lines
2.6 KiB
Markdown
---
|
|
title: Use @collection for Cross-Collection Lookups
|
|
impact: HIGH
|
|
impactDescription: Enables complex authorization without denormalization
|
|
tags: api-rules, security, cross-collection, relations
|
|
---
|
|
|
|
## Use @collection for Cross-Collection Lookups
|
|
|
|
The `@collection` reference allows rules to query other collections, enabling complex authorization patterns like role-based access, team membership, and resource permissions.
|
|
|
|
**Incorrect (denormalizing data for access control):**
|
|
|
|
```javascript
|
|
// Duplicating team membership in every resource
|
|
const documentsSchema = [
|
|
{ name: 'title', type: 'text' },
|
|
{ name: 'team', type: 'relation' },
|
|
// Duplicated member list for access control - gets out of sync!
|
|
{ name: 'allowedUsers', type: 'relation', options: { maxSelect: 999 } }
|
|
];
|
|
|
|
// Rule checks duplicated data
|
|
listRule: 'allowedUsers ?= @request.auth.id'
|
|
// Problem: must update allowedUsers whenever team membership changes
|
|
```
|
|
|
|
**Correct (using @collection lookup):**
|
|
|
|
```javascript
|
|
// Clean schema - no duplication
|
|
const documentsSchema = [
|
|
{ name: 'title', type: 'text' },
|
|
{ name: 'team', type: 'relation', options: { collectionId: 'teams' } }
|
|
];
|
|
|
|
// Check team membership via @collection lookup
|
|
listRule: '@collection.team_members.user ?= @request.auth.id && @collection.team_members.team ?= team'
|
|
|
|
// Alternative: check if user is in team's members array
|
|
listRule: 'team.members ?= @request.auth.id'
|
|
|
|
// Role-based access via separate roles collection
|
|
listRule: '@collection.user_roles.user = @request.auth.id && @collection.user_roles.role = "admin"'
|
|
```
|
|
|
|
**Common patterns:**
|
|
|
|
```javascript
|
|
// Team-based access
|
|
// teams: { name, members (relation to users) }
|
|
// documents: { title, team (relation to teams) }
|
|
viewRule: 'team.members ?= @request.auth.id'
|
|
|
|
// Organization hierarchy
|
|
// orgs: { name }
|
|
// org_members: { org, user, role }
|
|
// projects: { name, org }
|
|
listRule: '@collection.org_members.org = org && @collection.org_members.user = @request.auth.id'
|
|
|
|
// Permission-based access
|
|
// permissions: { resource, user, level }
|
|
updateRule: '@collection.permissions.resource = id && @collection.permissions.user = @request.auth.id && @collection.permissions.level = "write"'
|
|
|
|
// Using aliases for complex queries
|
|
listRule: '@collection.memberships:m.user = @request.auth.id && @collection.memberships:m.team = team'
|
|
```
|
|
|
|
**Performance considerations:**
|
|
- Cross-collection lookups add query complexity
|
|
- Ensure referenced fields are indexed
|
|
- Consider caching for frequently accessed permissions
|
|
- Test performance with realistic data volumes
|
|
|
|
Reference: [PocketBase Collection Reference](https://pocketbase.io/docs/api-rules-and-filters/#collection-fields)
|