FQL语法基础 #

一、FQL概述 #

1.1 什么是FQL #

FQL(Fauna Query Language)是FaunaDB的原生查询语言,采用函数式编程风格。

text
FQL特点:
├── 函数式编程风格
├── 表达式组合
├── 类型安全
├── 丰富的内置函数
├── 支持用户定义函数
└── 支持事务

1.2 FQL vs SQL #

特性 FQL SQL
风格 函数式 声明式
组合 嵌套表达式 子查询
类型 动态类型 静态类型
事务 原生支持 需要显式声明

二、基本语法 #

2.1 表达式 #

FQL由表达式组成,每个表达式返回一个值。

javascript
// 简单表达式
"Hello World"          // 字符串
123                    // 数字
true                   // 布尔值
null                   // 空值

// 复合表达式
Add(1, 2, 3)           // 返回 6
Concat(["a", "b"])     // 返回 "ab"

2.2 函数调用 #

javascript
// 基本函数调用
FunctionName(arg1, arg2, ...)

// 示例
Add(1, 2)
Concat("Hello", " ", "World")
Lower("HELLO")

2.3 嵌套表达式 #

javascript
// 表达式嵌套
Add(Multiply(2, 3), 4)  // 2*3 + 4 = 10

// 查询嵌套
Get(
  Ref(
    Collection("users"),
    "123456"
  )
)

三、数据类型 #

3.1 标量类型 #

javascript
// 字符串
"Hello World"
'Hello World'

// 数字
42
3.14
-100

// 布尔
true
false

// 空值
null

3.2 集合类型 #

javascript
// 数组
[1, 2, 3, 4, 5]
["a", "b", "c"]
[{ name: "Tom" }, { name: "Jerry" }]

// 对象
{
  name: "Tom",
  age: 30,
  active: true
}

3.3 特殊类型 #

javascript
// 引用
Ref(Collection("users"), "123456")

// 时间戳
Time("2024-01-01T00:00:00Z")
Now()

// 日期
Date("2024-01-01")

// 数据库引用
Database("my_database")

// 集合引用
Collection("users")

// 索引引用
Index("users_by_email")

四、常用函数 #

4.1 数学函数 #

javascript
// 加法
Add(1, 2, 3)              // 6

// 减法
Subtract(10, 3)           // 7

// 乘法
Multiply(2, 3, 4)         // 24

// 除法
Divide(10, 2)             // 5

// 取模
Modulo(10, 3)             // 1

// 绝对值
Abs(-5)                   // 5

// 最大/最小值
Max(1, 5, 3, 2)           // 5
Min(1, 5, 3, 2)           // 1

// 四舍五入
Round(3.14159, 2)         // 3.14

// 向上/向下取整
Ceil(3.2)                 // 4
Floor(3.8)                // 3

4.2 字符串函数 #

javascript
// 连接
Concat(["Hello", " ", "World"])  // "Hello World"

// 转换大小写
Upper("hello")                   // "HELLO"
Lower("HELLO")                   // "hello"

// 字符串长度
Length("Hello")                  // 5

// 子字符串
Substring("Hello World", 0, 5)   // "Hello"

// 替换
ReplaceStr("Hello World", "World", "Fauna")  // "Hello Fauna"

// 正则匹配
Regex("Hello123", "[0-9]+")      // true

// 分割
Split("a,b,c", ",")              // ["a", "b", "c"]

// 去除空白
Trim("  Hello  ")                // "Hello"

// 字符串格式化
Format("Hello %s, you are %d years old", "Tom", 30)
// "Hello Tom, you are 30 years old"

4.3 数组函数 #

javascript
// 数组长度
Count([1, 2, 3, 4, 5])           // 5

// 是否包含
ContainsValue([1, 2, 3], 2)      // true

// 数组连接
Append([1, 2], [3, 4])           // [1, 2, 3, 4]

// 数组前置
Prepend([1, 2], [3, 4])          // [1, 2, 3, 4]

// 获取元素
Select(0, ["a", "b", "c"])       // "a"

// 过滤
Filter(
  [1, 2, 3, 4, 5],
  Lambda("x", GT(Var("x"), 2))
)                                // [3, 4, 5]

// 映射
Map(
  [1, 2, 3],
  Lambda("x", Multiply(Var("x"), 2))
)                                // [2, 4, 6]

// 归约
Reduce(
  [1, 2, 3, 4, 5],
  Lambda((acc, val) => Add(acc, val)),
  0
)                                // 15

4.4 对象函数 #

javascript
// 合并对象
Merge(
  { a: 1, b: 2 },
  { b: 3, c: 4 }
)                                // { a: 1, b: 3, c: 4 }

// 选择属性
Select(["name"], { name: "Tom", age: 30 })  // "Tom"

// 检查属性存在
ContainsPath({ a: { b: 1 } }, ["a", "b"])   // true

// 获取所有键
Keys({ a: 1, b: 2, c: 3 })       // ["a", "b", "c"]

// 获取所有值
Values({ a: 1, b: 2, c: 3 })     // [1, 2, 3]

五、逻辑控制 #

5.1 条件表达式 #

javascript
// If表达式
If(
  GT(5, 3),
  "greater",
  "not greater"
)                                // "greater"

// 嵌套条件
If(
  LT(age, 18),
  "minor",
  If(
    LT(age, 65),
    "adult",
    "senior"
  )
)

5.2 逻辑运算 #

javascript
// 与
And(true, true, false)           // false

// 或
Or(false, false, true)           // true

// 非
Not(true)                        // false

// 组合使用
And(
  GT(age, 18),
  LT(age, 65),
  Equals(status, "active")
)

5.3 比较运算 #

javascript
// 相等
Equals("a", "a")                 // true

// 不等
Not(Equals("a", "b"))            // true

// 大于/小于
GT(5, 3)                         // true
GTE(5, 5)                        // true
LT(3, 5)                         // true
LTE(5, 5)                        // true

六、Lambda表达式 #

6.1 Lambda语法 #

javascript
// 基本语法
Lambda("param", expression)

// 多参数
Lambda(
  ["param1", "param2"],
  expression
)

// 解构参数
Lambda(
  { name: "name", age: "age" },
  expression
)

6.2 Lambda使用 #

javascript
// 在Map中使用
Map(
  [1, 2, 3, 4, 5],
  Lambda("x", Multiply(Var("x"), 2))
)
// 结果: [2, 4, 6, 8, 10]

// 在Filter中使用
Filter(
  [1, 2, 3, 4, 5],
  Lambda("x", GT(Var("x"), 2))
)
// 结果: [3, 4, 5]

// 多参数Lambda
Map(
  [[1, 2], [3, 4], [5, 6]],
  Lambda(
    ["a", "b"],
    Add(Var("a"), Var("b"))
  )
)
// 结果: [3, 7, 11]

6.3 Var函数 #

javascript
// 使用Var获取Lambda参数
Lambda("x", Var("x"))            // 返回参数x的值

// 嵌套使用
Lambda("x",
  Lambda("y",
    Add(Var("x"), Var("y"))
  )
)

七、Let绑定 #

7.1 基本语法 #

javascript
// Let绑定变量
Let(
  {
    x: 10,
    y: 20
  },
  Add(Var("x"), Var("y"))
)                                // 30

7.2 链式绑定 #

javascript
// 变量依赖
Let(
  {
    a: 10,
    b: Add(Var("a"), 5),        // b = 15
    c: Multiply(Var("b"), 2)    // c = 30
  },
  Var("c")
)                                // 30

7.3 实际应用 #

javascript
// 复杂查询中使用Let
Let(
  {
    user: Get(Ref(Collection("users"), "123456")),
    orders: Paginate(
      Match(Index("orders_by_user"), Select(["ref"], Var("user")))
    )
  },
  {
    user: Var("user"),
    orderCount: Count(Var("orders"))
  }
)

八、Do表达式 #

8.1 基本用法 #

javascript
// Do执行多个操作,返回最后一个
Do(
  Create(Collection("logs"), { data: { action: "create_user" } }),
  Create(Collection("users"), { data: { name: "Tom" } })
)
// 返回创建的用户文档

8.2 实际应用 #

javascript
// 创建用户并记录日志
Do(
  Create(Collection("users"), {
    data: { name: "Tom", email: "tom@example.com" }
  }),
  Create(Collection("audit_logs"), {
    data: {
      action: "user_created",
      timestamp: Now()
    }
  })
)

九、错误处理 #

9.1 Abort #

javascript
// Abort中止事务
If(
  LT(balance, amount),
  Abort("Insufficient balance"),
  Do(
    Update(userRef, { data: { balance: Subtract(balance, amount) } }),
    Create(Collection("transactions"), { data: { amount: amount } })
  )
)

9.2 错误处理模式 #

javascript
// 检查文档是否存在
Let(
  {
    doc: If(
      Exists(Ref(Collection("users"), "123456")),
      Get(Ref(Collection("users"), "123456")),
      null
    )
  },
  If(
    Equals(Var("doc"), null),
    { error: "Document not found" },
    Var("doc")
  )
)

十、分页 #

10.1 Paginate #

javascript
// 基本分页
Paginate(Match(Index("all_users")))

// 设置大小
Paginate(
  Match(Index("all_users")),
  { size: 10 }
)

// 设置游标
Paginate(
  Match(Index("all_users")),
  {
    size: 10,
    after: Ref(Collection("users"), "123456")
  }
)

// 反向分页
Paginate(
  Match(Index("all_users")),
  {
    size: 10,
    before: Ref(Collection("users"), "654321")
  }
)

10.2 分页结果 #

javascript
// 分页返回格式
{
  data: [...],
  after: ...,    // 下一页游标
  before: ...    // 上一页游标
}

十一、命名规范 #

11.1 集合命名 #

text
集合命名规范:
├── 使用小写字母
├── 使用下划线分隔
├── 使用复数形式
└── 示例:users, products, order_items

11.2 索引命名 #

text
索引命名规范:
├── 描述性名称
├── 包含查询字段
├── 使用下划线分隔
└── 示例:users_by_email, products_by_category

11.3 函数命名 #

text
函数命名规范:
├── 使用动词开头
├── 描述功能
├── 使用下划线分隔
└── 示例:create_user, get_user_orders

十二、最佳实践 #

12.1 代码组织 #

javascript
// 使用Let组织复杂查询
Let(
  {
    // 步骤1:获取用户
    user: Get(userRef),
    
    // 步骤2:获取用户订单
    orders: Paginate(
      Match(Index("orders_by_user"), Select(["ref"], Var("user"))),
      { size: 10 }
    ),
    
    // 步骤3:计算统计
    stats: {
      totalOrders: Count(Var("orders")),
      userStatus: Select(["data", "status"], Var("user"))
    }
  },
  // 返回结果
  {
    user: Var("user"),
    orders: Var("orders"),
    stats: Var("stats")
  }
)

12.2 性能优化 #

javascript
// 避免N+1查询
Let(
  {
    users: Paginate(Match(Index("all_users")), { size: 100 }),
    enrichedUsers: Map(
      Var("users"),
      Lambda("userRef",
        Let(
          {
            user: Get(Var("userRef")),
            orderCount: Count(
              Match(Index("orders_by_user"), Var("userRef"))
            )
          },
          Merge(Var("user"), { orderCount: Var("orderCount") })
        )
      )
    )
  },
  Var("enrichedUsers")
)

十三、总结 #

FQL语法要点:

特性 说明
表达式 一切皆表达式
函数 丰富的内置函数
Lambda 匿名函数
Let 变量绑定
Do 顺序执行
If 条件判断

下一步,让我们学习数据类型!

最后更新:2026-03-27