schema-builder

安装量: 545
排名: #2005

安装

npx skills add https://github.com/get-convex/agent-skills --skill schema-builder
Convex Schema Builder
Build well-structured Convex schemas following best practices for relationships, indexes, and validators.
When to Use
Creating a new
convex/schema.ts
file
Adding tables to existing schema
Designing data model relationships
Adding or optimizing indexes
Converting nested data to relational structure
Schema Design Principles
Document-Relational
Use flat documents with ID references, not deep nesting
Index Foreign Keys
Always index fields used in lookups (userId, teamId, etc.)
Limit Arrays
Only use arrays for small, bounded collections (<8192 items)
Type Safety
Use strict validators with
v.*
types
Schema Template
import
{
defineSchema
,
defineTable
}
from
"convex/server"
;
import
{
v
}
from
"convex/values"
;
export
default
defineSchema
(
{
tableName
:
defineTable
(
{
// Required fields
field
:
v
.
string
(
)
,
// Optional fields
optional
:
v
.
optional
(
v
.
number
(
)
)
,
// Relations (use IDs)
userId
:
v
.
id
(
"users"
)
,
// Enums with union + literal
status
:
v
.
union
(
v
.
literal
(
"active"
)
,
v
.
literal
(
"pending"
)
,
v
.
literal
(
"archived"
)
)
,
// Timestamps
createdAt
:
v
.
number
(
)
,
updatedAt
:
v
.
optional
(
v
.
number
(
)
)
,
}
)
// Index for queries by this field
.
index
(
"by_user"
,
[
"userId"
]
)
// Compound index for common query patterns
.
index
(
"by_user_and_status"
,
[
"userId"
,
"status"
]
)
// Index for time-based queries
.
index
(
"by_created"
,
[
"createdAt"
]
)
,
}
)
;
Common Patterns
One-to-Many Relationship
export
default
defineSchema
(
{
users
:
defineTable
(
{
name
:
v
.
string
(
)
,
email
:
v
.
string
(
)
,
}
)
.
index
(
"by_email"
,
[
"email"
]
)
,
posts
:
defineTable
(
{
userId
:
v
.
id
(
"users"
)
,
title
:
v
.
string
(
)
,
content
:
v
.
string
(
)
,
}
)
.
index
(
"by_user"
,
[
"userId"
]
)
,
}
)
;
Many-to-Many with Junction Table
export
default
defineSchema
(
{
users
:
defineTable
(
{
name
:
v
.
string
(
)
,
}
)
,
projects
:
defineTable
(
{
name
:
v
.
string
(
)
,
}
)
,
projectMembers
:
defineTable
(
{
userId
:
v
.
id
(
"users"
)
,
projectId
:
v
.
id
(
"projects"
)
,
role
:
v
.
union
(
v
.
literal
(
"owner"
)
,
v
.
literal
(
"member"
)
)
,
}
)
.
index
(
"by_user"
,
[
"userId"
]
)
.
index
(
"by_project"
,
[
"projectId"
]
)
.
index
(
"by_project_and_user"
,
[
"projectId"
,
"userId"
]
)
,
}
)
;
Hierarchical Data
export
default
defineSchema
(
{
comments
:
defineTable
(
{
postId
:
v
.
id
(
"posts"
)
,
parentId
:
v
.
optional
(
v
.
id
(
"comments"
)
)
,
// null for top-level
userId
:
v
.
id
(
"users"
)
,
text
:
v
.
string
(
)
,
}
)
.
index
(
"by_post"
,
[
"postId"
]
)
.
index
(
"by_parent"
,
[
"parentId"
]
)
,
}
)
;
Small Bounded Arrays (OK to use)
export
default
defineSchema
(
{
users
:
defineTable
(
{
name
:
v
.
string
(
)
,
// Small, bounded collections are fine
roles
:
v
.
array
(
v
.
union
(
v
.
literal
(
"admin"
)
,
v
.
literal
(
"editor"
)
,
v
.
literal
(
"viewer"
)
)
)
,
tags
:
v
.
array
(
v
.
string
(
)
)
,
// e.g., max 10 tags
}
)
,
}
)
;
Validator Reference
// Primitives
v
.
string
(
)
v
.
number
(
)
v
.
boolean
(
)
v
.
null
(
)
v
.
id
(
"tableName"
)
// Optional
v
.
optional
(
v
.
string
(
)
)
// Union types (enums)
v
.
union
(
v
.
literal
(
"a"
)
,
v
.
literal
(
"b"
)
)
// Objects
v
.
object
(
{
key
:
v
.
string
(
)
,
nested
:
v
.
number
(
)
,
}
)
// Arrays
v
.
array
(
v
.
string
(
)
)
// Records (arbitrary keys)
v
.
record
(
v
.
string
(
)
,
v
.
boolean
(
)
)
// Any (avoid if possible)
v
.
any
(
)
Index Strategy
Single-field indexes
For simple lookups
by_user: ["userId"]
by_email: ["email"]
Compound indexes
For filtered queries by_user_and_status: ["userId", "status"] by_team_and_created: ["teamId", "createdAt"] Remove redundant : by_a_and_b usually covers by_a Checklist All foreign keys have indexes Common query patterns have compound indexes Arrays are small and bounded (or converted to relations) All fields have proper validators Enums use v.union(v.literal(...)) pattern Timestamps use v.number() (milliseconds since epoch) Migration from Nested to Relational If converting from nested structures: Before: users : defineTable ( { posts : v . array ( v . object ( { title : v . string ( ) , comments : v . array ( v . object ( { text : v . string ( ) } ) ) , } ) ) , } ) After: users : defineTable ( { name : v . string ( ) , } ) , posts : defineTable ( { userId : v . id ( "users" ) , title : v . string ( ) , } ) . index ( "by_user" , [ "userId" ] ) , comments : defineTable ( { postId : v . id ( "posts" ) , text : v . string ( ) , } ) . index ( "by_post" , [ "postId" ] ) ,
返回排行榜