OOro

JSON 与全文索引

使用统一表达式查询 JSON 字段、JSONRaw 输出、全文索引定义、全文查询和方言差异。

JSON 和全文检索是数据库差异较大的能力。Oro 提供统一 API,但不同驱动的底层能力仍然会影响可用性和性能。

JSON 字段定义

type Product struct {
    oro.Model
    Code string
    Meta oro.JSONRaw
}

func (Product) Define(s *oro.SchemaBuilder) {
    s.Table("products")
    s.Field("Code").String().Unique()
    s.Field("Meta").JSON().Nullable()
}

oro.JSONRaw 适合保存原始 JSON 数据。也可以使用 []bytestring 或应用层自定义类型,但 JSONRaw 在序列化时能避免二次转义。

JSON 路径条件

模型查询使用 Go 字段名:

rows, err := db.Use[Product]().Where(
    oro.JSON("Meta").Path("profile", "country").Eq("CN"),
).Get(ctx)

布尔值:

rows, err := db.Use[Product]().Where(
    oro.JSON("Meta").Path("flags", "featured").Eq(true),
).Get(ctx)

裸表查询使用数据库列名:

rows, err := db.Table("products").Where(
    oro.JSON("meta").Path("profile", "country").Eq("CN"),
).Get(ctx)

JSON 条件方法

方法 用途
Eq(value) 路径值相等
NotEq(value) 路径值不等
IsNull() 路径值为空
IsNotNull() 路径值非空
Exists() 路径存在
Contains(value) JSON 包含,取决于驱动支持
Like(value) 对路径文本值执行 SQL LIKE,支持 SQLite/MySQL/PostgreSQL

示例:

products, err := db.Use[Product]().Where(
    oro.JSON("Meta").Path("tags").Contains("featured"),
).Get(ctx)
products, err := db.Use[Product]().Where(
    oro.JSON("Meta").Path("profile", "city").Like("%Shanghai%"),
).Get(ctx)

JSON 输出

payload := oro.Serialize(product)

如果字段是 oro.JSONRawSerialize 会输出 json.RawMessage,避免把 JSON 当字符串输出。

全文索引定义

字段级全文索引:

func (Post) Define(s *oro.SchemaBuilder) {
    s.Table("posts")
    s.Field("Title").String().FullText()
    s.Field("Body").Text()
}

组合全文索引:

func (Post) Define(s *oro.SchemaBuilder) {
    s.FullText("ft_posts_title_body", "Title", "Body")
}

组合索引字段使用 Go 字段名。

全文查询

posts, err := db.Use[Post]().Where(
    oro.FullText("Title", "Body").Match("generic orm"),
).Get(ctx)

裸表查询使用数据库列名:

posts, err := db.Table("posts").Where(
    oro.FullText("title", "body").Match("generic orm"),
).Get(ctx)

相关度分数

posts, err := db.Use[Post]().
    Select(
        "ID",
        "Title",
        oro.FullText("Title", "Body").Score("generic orm").As("score"),
    ).
    Where(oro.FullText("Title", "Body").Match("generic orm")).
    OrderByDesc("score").
    Get(ctx)

Score(...).As(alias) 用于把相关度作为选择字段输出。

方言说明

驱动 JSON 全文索引
SQLite 依赖 SQLite 构建是否启用 JSON 函数 普通表全文索引 DDL 不统一,建议专门 FTS 表
MySQL 支持 JSON 路径和 contains 类能力 依赖 engine/version 的原生全文索引
PostgreSQL JSON/JSONB 风格提取 编译为 to_tsvector / plainto_tsquery 类语法

如果当前驱动不支持某个能力,会返回 oro.ErrUnsupported

性能建议

  • JSON 路径查询要关注数据库是否能使用表达式索引;
  • 高频筛选字段不要盲目塞进 JSON,应该拆成普通列;
  • 全文检索要建全文索引,不要在大表上无索引 match;
  • SQLite 的全文检索建议使用独立 FTS 表和 Raw SQL;
  • 多语言分词、权重和排序通常需要数据库级定制,Oro 只提供基础统一表达。
编辑此页