mcpField
S
surrealdb

surrealdb

github.com/tyrchenデータ・データベース4540 回インストール28 週間前に更新
リポジトリ

surrealdb について

SurrealDB アプリケーション向けのクエリ生成スキルです。SurrealQL の作成に加え、スキーマや関係、認証、パフォーマンスの設計を支援します。

主な機能

  1. 01CRUD とグラフクエリの生成
  2. 02テーブル、フィールド、関係の設計
  3. 03認証と権限ルールの作成
  4. 04インデックスとトランザクションの計画
  5. 05クエリのデバッグと最適化

活用シーン

  1. 01SurrealDB のデータモデル作成
  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. どのようなリレーションシップがありますか?(1 対多、多対多、グラフのトラバーサルですか?)
  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;

E コマース - 商品のおすすめ:

-- 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;
E コマーススキーマ
-- 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 のバージョンを必ず確認してください。

コメント