mcpField
S
surrealdb

surrealdb

github.com/tyrchen数据与数据库4540 次安装28 周前更新
代码仓库

关于 surrealdb

面向 SurrealDB 多模型应用的查询生成技能,可编写和优化 SurrealQL,并指导架构、关系、认证与性能设计。

主要功能

  1. 01生成 CRUD 与图查询
  2. 02设计表、字段和关系
  3. 03编写认证与权限规则
  4. 04规划索引和事务
  5. 05调试并优化查询

适用场景

  1. 01创建 SurrealDB 数据模型
  2. 02构建关系遍历和实时查询
  3. 03迁移或优化现有查询

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/tyrchen/claude-skills --skill surrealdb

安装后在 Claude Code 中输入/surrealdb确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
graph_relationships.md
schema_patterns.md
security_auth.md
surrealql_syntax.md

详细介绍

SurrealDB - 可用于生产环境的查询生成器

使用 SurrealQL 为文档、图和关系模式等多模型数据库应用生成稳健、高质量、可用于生产环境的 SurrealDB 查询和操作。

何时使用此技能

当用户想要执行以下操作时,使用此技能:

  • 编写 SurrealQL 查询(SELECT、CREATE、UPDATE、DELETE、UPSERT)
  • 设计数据库架构(SCHEMAFULL/SCHEMALESS 表、字段定义)
  • 建模关系(记录链接、使用 RELATE 创建图边、嵌套数据)
  • 实现身份验证(DEFINE ACCESS、SCOPE、权限、RBAC)
  • 创建索引以优化性能
  • 使用 DEFINE FUNCTION 编写自定义函数
  • 使用 LIVE 查询构建实时应用
  • 实现事务以确保数据一致性
  • 从 SQL/NoSQL 迁移到 SurrealDB
  • 调试或优化现有 SurrealQL

SurrealQL 快速参考

核心语句语法
-- SELECT with graph traversal
SELECT *, ->friends->person AS mutual_friends FROM person:alice;

-- CREATE with specific ID
CREATE person:john SET name = 'John', age = 30;

-- UPDATE with operators
UPDATE person SET age += 1, tags += 'senior' WHERE age >= 65;

-- DELETE with conditions
DELETE person WHERE active = false;

-- UPSERT (create if not exists, update if exists)
UPSERT user:[email protected] SET email = '[email protected]', visits += 1;

-- RELATE for graph edges
RELATE person:alice->follows->person:bob SET since = time::now();
数据类型
-- Basic types
string, int, float, bool, datetime, duration, decimal, uuid

-- Complex types
array, object, record<table>, option<type>

-- Special types
geometry (point, line, polygon), bytes, null, none
常用函数
-- Time functions
time::now()                    -- Current timestamp
time::floor(datetime, 1d)      -- Floor to day
duration::from::days(7)        -- Create duration

-- String functions
string::is::email($value)      -- Validate email
string::concat($a, ' ', $b)    -- Concatenate
string::split($s, ',')         -- Split to array
string::lowercase($s)          -- Lowercase

-- Array functions
array::len($arr)               -- Array length
array::push($arr, $item)       -- Add to array
array::distinct($arr)          -- Remove duplicates
array::flatten($arr)           -- Flatten nested arrays

-- Crypto functions
crypto::argon2::generate($password)           -- Hash password
crypto::argon2::compare($hash, $password)     -- Verify password

-- Math functions
math::sum($arr)                -- Sum values
math::mean($arr)               -- Average
math::max($arr)                -- Maximum

-- Record functions
record::id($record)            -- Get record ID
record::table($record)         -- Get table name

-- Type functions
type::is::string($val)         -- Type check
type::thing($table, $id)       -- Create record ID

SurrealDB 查询编写说明

步骤 1:了解数据模型

编写任何 SurrealQL 之前:

  1. 数据结构是什么?(文档、图、关系型还是混合型?)
  2. 存在哪些关系?(一对多、多对多、图遍历?)
  3. 有哪些访问模式?(读密集型、写密集型、实时?)
  4. 一致性要求是什么?(最终一致性、强一致性、事务性?)
步骤 2:选择架构策略

SCHEMAFULL - 适用于:

  • 数据结构定义明确
  • 类型安全至关重要
  • 需要验证规则
  • 生产工作负载

SCHEMALESS - 适用于:

  • 快速原型开发
  • 数据结构不断演进
  • 灵活的文档存储
-- SCHEMAFULL with validation
DEFINE TABLE user SCHEMAFULL;
DEFINE FIELD email ON user TYPE string ASSERT string::is::email($value);
DEFINE FIELD password ON user TYPE string;
DEFINE FIELD created_at ON user TYPE datetime DEFAULT time::now();
DEFINE FIELD status ON user TYPE string DEFAULT 'active'
    ASSERT $value IN ['active', 'inactive', 'suspended'];

-- SCHEMALESS (flexible)
DEFINE TABLE event SCHEMALESS;
步骤 3:设计关系

选择合适的关系模型:

记录链接 - 简单、直接的引用:

-- One-to-many via array of record IDs
CREATE user:alice SET
    name = 'Alice',
    friends = [user:bob, user:carol];

-- Fetch with link resolution
SELECT *, friends.* FROM user:alice;

图边(RELATE) - 包含元数据的复杂关系:

-- Create relationship with properties
RELATE user:alice->follows->user:bob SET
    since = time::now(),
    notifications = true;

-- Traverse graph
SELECT
    ->follows->user AS following,
    <-follows<-user AS followers
FROM user:alice;

-- Multi-hop traversal
SELECT ->follows->user->follows->user AS friends_of_friends
FROM user:alice;

嵌入式文档 - 反规范化数据:

CREATE order SET
    customer = { name: 'Alice', email: '[email protected]' },
    items = [
        { product: 'Widget', quantity: 2, price: 29.99 },
        { product: 'Gadget', quantity: 1, price: 49.99 }
    ],
    total = 109.97;
步骤 4:实现身份验证

使用 DEFINE ACCESS 实现记录级访问控制:

-- Define user access
DEFINE ACCESS user_auth ON DATABASE TYPE RECORD
    SIGNUP (
        CREATE user SET
            email = $email,
            password = crypto::argon2::generate($password),
            created_at = time::now()
    )
    SIGNIN (
        SELECT * FROM user
        WHERE email = $email
        AND crypto::argon2::compare(password, $password)
    )
    DURATION FOR TOKEN 24h, FOR SESSION 7d;

-- Define table permissions
DEFINE TABLE post SCHEMAFULL
    PERMISSIONS
        FOR select WHERE published = true OR author = $auth.id
        FOR create WHERE $auth.id != NONE
        FOR update WHERE author = $auth.id
        FOR delete WHERE author = $auth.id;
步骤 5:使用索引优化
-- Unique index
DEFINE INDEX unique_email ON user FIELDS email UNIQUE;

-- Composite index
DEFINE INDEX order_lookup ON order FIELDS customer, status;

-- Full-text search index
DEFINE ANALYZER english TOKENIZERS blank FILTERS lowercase, snowball(english);
DEFINE INDEX content_search ON article FIELDS content
    SEARCH ANALYZER english BM25;

-- Verify index usage
EXPLAIN SELECT * FROM user WHERE email = '[email protected]';
步骤 6:编写事务
BEGIN TRANSACTION;

-- Transfer funds between accounts
LET $amount = 100;
UPDATE account:alice SET balance -= $amount;
UPDATE account:bob SET balance += $amount;
CREATE transaction SET
    from = account:alice,
    to = account:bob,
    amount = $amount,
    timestamp = time::now();

COMMIT TRANSACTION;

常见查询模式

CRUD 操作

带验证的创建:

CREATE user CONTENT {
    email: '[email protected]',
    name: 'John Doe',
    roles: ['user'],
    metadata: {
        source: 'signup',
        ip: '192.168.1.1'
    }
};

带筛选和分页的查询:

SELECT * FROM user
WHERE status = 'active'
    AND created_at > time::now() - 30d
ORDER BY created_at DESC
LIMIT 20
START 0;

使用运算符更新:

-- Increment/decrement
UPDATE user:alice SET login_count += 1;

-- Array manipulation
UPDATE user:alice SET tags += 'premium', tags -= 'trial';

-- Conditional update
UPDATE user SET status = 'inactive'
WHERE last_login < time::now() - 90d;

插入或更新模式:

UPSERT user:[email protected] SET
    email = '[email protected]',
    last_seen = time::now(),
    visits += 1;
图查询

社交网络 - 朋友的朋友:

SELECT
    id,
    name,
    array::distinct(->follows->user->follows->user) AS suggested_friends
FROM user:alice
WHERE suggested_friends != user:alice;

电子商务 - 商品推荐:

-- Find products bought by users who bought this product
SELECT
    <-purchased<-user->purchased->product AS related_products,
    count() AS frequency
FROM product:widget123
GROUP BY related_products
ORDER BY frequency DESC
LIMIT 10;

知识图谱 - 递归遍历:

-- Find all ancestors up to 5 levels
SELECT
    ->parent->(1..5)->category AS ancestors
FROM category:electronics;
分析查询

聚合:

SELECT
    status,
    count() AS total,
    math::mean(age) AS avg_age,
    math::min(created_at) AS first_created
FROM user
GROUP BY status;

时间序列分析:

SELECT
    time::floor(timestamp, 1h) AS hour,
    count() AS events,
    math::sum(value) AS total_value
FROM metrics
WHERE timestamp > time::now() - 24h
GROUP BY hour
ORDER BY hour;
子查询和计算字段

SELECT 中的子查询:

SELECT
    *,
    (SELECT count() FROM post WHERE author = $parent.id) AS post_count,
    (SELECT VALUE title FROM post WHERE author = $parent.id LIMIT 5) AS recent_posts
FROM user;

使用 LET 编写复杂查询(CTE 的替代方案):

LET $active_users = (SELECT id FROM user WHERE status = 'active');
LET $recent_orders = (SELECT * FROM order WHERE created_at > time::now() - 7d);

SELECT * FROM $recent_orders
WHERE customer IN $active_users.id;

架构设计模式

带嵌套对象的用户资料
DEFINE TABLE user SCHEMAFULL;
DEFINE FIELD email ON user TYPE string ASSERT string::is::email($value);
DEFINE FIELD password ON user TYPE string;
DEFINE FIELD profile ON user TYPE object;
DEFINE FIELD profile.name ON user TYPE string;
DEFINE FIELD profile.avatar ON user TYPE option<string>;
DEFINE FIELD profile.bio ON user TYPE option<string>;
DEFINE FIELD settings ON user TYPE object DEFAULT {};
DEFINE FIELD settings.notifications ON user TYPE bool DEFAULT true;
DEFINE FIELD settings.theme ON user TYPE string DEFAULT 'light';
DEFINE FIELD created_at ON user TYPE datetime DEFAULT time::now();
DEFINE FIELD updated_at ON user TYPE datetime VALUE time::now();

DEFINE INDEX unique_email ON user FIELDS email UNIQUE;
电子商务架构
-- Products
DEFINE TABLE product SCHEMAFULL;
DEFINE FIELD name ON product TYPE string;
DEFINE FIELD description ON product TYPE string;
DEFINE FIELD price ON product TYPE decimal;
DEFINE FIELD inventory ON product TYPE int DEFAULT 0;
DEFINE FIELD categories ON product TYPE array<record<category>>;
DEFINE FIELD active ON product TYPE bool DEFAULT true;

DEFINE INDEX product_search ON product FIELDS name, description
    SEARCH ANALYZER blank BM25;

-- Orders
DEFINE TABLE order SCHEMAFULL;
DEFINE FIELD customer ON order TYPE record<user>;
DEFINE FIELD items ON order TYPE array;
DEFINE FIELD items.*.product ON order TYPE record<product>;
DEFINE FIELD items.*.quantity ON order TYPE int;
DEFINE FIELD items.*.price ON order TYPE decimal;
DEFINE FIELD status ON order TYPE string DEFAULT 'pending'
    ASSERT $value IN ['pending', 'processing', 'shipped', 'delivered', 'cancelled'];
DEFINE FIELD total ON order TYPE decimal;
DEFINE FIELD created_at ON order TYPE datetime DEFAULT time::now();

DEFINE INDEX order_customer ON order FIELDS customer;
DEFINE INDEX order_status ON order FIELDS status, created_at;
图关系架构
-- Define edge table
DEFINE TABLE follows SCHEMAFULL TYPE RELATION;
DEFINE FIELD in ON follows TYPE record<user>;
DEFINE FIELD out ON follows TYPE record<user>;
DEFINE FIELD since ON follows TYPE datetime DEFAULT time::now();
DEFINE FIELD notifications ON follows TYPE bool DEFAULT true;

-- Prevent duplicate follows
DEFINE INDEX unique_follow ON follows FIELDS in, out UNIQUE;

自定义函数

-- Calculate user engagement score
DEFINE FUNCTION fn::engagement_score($user_id: record<user>) {
    LET $posts = (SELECT count() FROM post WHERE author = $user_id);
    LET $comments = (SELECT count() FROM comment WHERE author = $user_id);
    LET $likes_received = (SELECT count() FROM like WHERE post.author = $user_id);

    RETURN ($posts * 5) + ($comments * 2) + $likes_received;
};

-- Usage
SELECT *, fn::engagement_score(id) AS score FROM user;

-- Validate and normalize email
DEFINE FUNCTION fn::normalize_email($email: string) {
    IF !string::is::email($email) {
        THROW "Invalid email format";
    };
    RETURN string::lowercase(string::trim($email));
};

-- Pagination helper
DEFINE FUNCTION fn::paginate($table: string, $page: int, $per_page: int) {
    LET $offset = ($page - 1) * $per_page;
    RETURN (SELECT * FROM type::table($table) LIMIT $per_page START $offset);
};

实时(LIVE 查询)

-- Subscribe to changes on a table
LIVE SELECT * FROM post WHERE published = true;

-- Subscribe to specific record changes
LIVE SELECT * FROM user:alice;

-- Subscribe with graph traversal
LIVE SELECT *, ->comments->comment AS comments FROM post;

-- Kill a live query
KILL $live_query_id;

性能最佳实践

1. 使用特定记录 ID,而非全表扫描
-- FAST: Direct ID access
SELECT * FROM user:alice;

-- SLOW: Table scan
SELECT * FROM user WHERE id = 'alice';
2. 只选择所需字段
-- BETTER: Specific fields
SELECT name, email FROM user;

-- AVOID: All fields when not needed
SELECT * FROM user;
3. 高效使用索引
-- Create index for common queries
DEFINE INDEX active_users ON user FIELDS status, created_at;

-- Query uses index
SELECT * FROM user
WHERE status = 'active'
ORDER BY created_at DESC;
4. 批量操作
-- BETTER: Single batch insert
INSERT INTO log [
    { level: 'info', message: 'Start' },
    { level: 'info', message: 'Processing' },
    { level: 'info', message: 'Complete' }
];

-- AVOID: Multiple separate inserts
5. 对相关操作使用事务
BEGIN TRANSACTION;
-- Multiple related operations
COMMIT TRANSACTION;

应避免的常见反模式

1. 未检查字段是否存在
-- WRONG: Field might not exist
SELECT * FROM user WHERE profile.name = 'John';

-- CORRECT: Check existence first (in application logic)
-- Or use SCHEMAFULL tables with proper defaults
2. N+1 查询问题
-- WRONG: Fetching related data in loops
-- (in application: for each user, fetch their posts)

-- CORRECT: Use record links and fetch in one query
SELECT *, posts.* FROM user FETCH posts;
3. 未使用合适的关系模型
-- WRONG: String IDs for relationships
CREATE user SET friend_ids = ['alice', 'bob'];

-- CORRECT: Record links
CREATE user SET friends = [user:alice, user:bob];
4. 图遍历导致获取过多数据
-- WRONG: Unbounded traversal
SELECT ->*->* FROM user:alice;

-- CORRECT: Bounded traversal
SELECT ->(1..3)->follows->user FROM user:alice;

调试和测试

解释查询执行过程
EXPLAIN SELECT * FROM user WHERE email = '[email protected]';
EXPLAIN FULL SELECT * FROM user WHERE email = '[email protected]';
检查表信息
INFO FOR TABLE user;
INFO FOR DB;
INFO FOR NS;
使用参数测试查询
LET $email = '[email protected]';
SELECT * FROM user WHERE email = $email;

输出格式

生成 SurrealDB 查询时,始终提供:

  1. 完整的 SurrealQL 语句,并确保语法正确
  2. 架构定义(创建表或字段时)
  3. 针对查询模式的索引建议
  4. 用于测试的示例数据
  5. 设计决策说明
  6. 相关的性能考量

参考文件

版本兼容性

  • SurrealDB 2.x:最新功能,支持 GraphQL,性能有所提升
  • SurrealDB 1.x:旧版,请使用 scope 代替 access

生成查询前,请务必确认目标 SurrealDB 版本。

评论

支持 Markdown