复杂数据查询 
本章节详细介绍基于数据模型处理器和 Query DSL 两种数据查询方式。建议在阅读前学习关系型数据库基础知识,了解 SQL 语法,可以编写基本的 SQL 语句。
使用 Model 处理器查询 
数据模型处理器 Find, Get, Paginate, UpdateWhere, DeleteWhere, DestroyWhere 均支持传入查询参数 Object QueryParam,对读取记录范围进行限定。
Object QueryParam:
JSON 描述:
json
{
  "select": ["id", "name", "mobile", "status"],
  "withs": {
    "manu": { "query": ["name", "short_name", "status"] },
    "addresses": {}
  },
  "wheres": [
    { "column": "status", "value": "enabled" },
    { "rel": "manu", "column": "status", "value": "enabled" },
    {
      "wheres": [
        { "column": "name", "value": "%张三%", "op": "like" },
        {
          "method": "orwhere",
          "column": "name",
          "value": "%李四%",
          "op": "like"
        }
      ]
    }
  ],
  "orders": [
    { "column": "id", "option": "desc" },
    { "rel": "manu", "column": "name" }
  ],
  "limit": 2
}引擎解析后的 SQL:
sql
SELECT
  `user`.`id`,`user`.`name`,`user`.`mobile`,`user`.`status`,
  `user_manu`.`name` AS `user_manu_name`,
  `user_manu`.`short_name` AS `user_manu_short_name` ,
  `user_manu`.`status` AS `user_manu_status`
FROM `user` AS `user`
LEFT JOIN `manu` AS `user_manu` ON `user_manu`.`id` = `user`.`manu_id`
WHERE  `user`.`status` = 'enabled'
AND `user_manu`.`status` = 'enabled'
AND (
   `user`.`name` like '%张三%' OR `user`.`name` like '%李四%'
)
ORDER BY `user`.`id` desc, `user_manu`.`name` asc
LIMIT 2数据结构说明:
QueryParam
| 字段 | 类型 | 说明 | 必填项 | 
|---|---|---|---|
| select | Array<String> | 选择字段清单 | 否 | 
| wheres | Array<Object Where> | 查询条件 | 否 | 
| orders | Array<Object Order> | 排序条件 | 否 | 
| limit | Integer | 返回记录条目 | 否 | 
| page | Integer | 当前页码 | 否 | 
| pagesize | Integer | 每页显示记录数量 | 否 | 
| withs | [key:String]:Object QueryParam | 读取关联模型 | 否 | 
Object Where
| 字段 | 类型 | 说明 | 必填项 | 
|---|---|---|---|
| rel | String | 如按关联模型的字段查询,则填写关联模型名称 | 否 | 
| column | String | 字段名称 | 否 | 
| method | String | 查询方法 where,orwhere 默认为 where | 否 | 
| op | String | 匹配关系 eq,like,in,gt 等 默认为 eq | 否 | 
| value | Any | 匹配数值 | 否 | 
| wheres | Array<Object Where> | 分组查询 | 否 | 
| 查询方法 | 说明 | 
|---|---|
| where | WHERE 字段 = 数值, WHERE 字段 >= 数值 | 
| orwhere | ... OR WHERE 字段 = 数值 | 
| 匹配关系 | 说明 | 
|---|---|
| eq | 默认值 等于 WHERE 字段 = 数值 | 
| like | 匹配 WHERE 字段 like 数值 | 
| match | 匹配 WHERE 字段 全文检索 数值 | 
| gt | 大于 WHERE 字段 > 数值 | 
| ge | 大于等于 WHERE 字段 >= 数值 | 
| lt | 小于 WHERE 字段 < 数值 | 
| le | 小于等于 WHERE 字段 <= 数值 | 
| null | 为空 WHERE 字段 IS NULL | 
| notnull | 不为空 WHERE 字段 IS NOT NULL | 
| in | 列表包含 WHERE 字段 IN (数值...) | 
| ne | 不等于匹配值 | 
Object Order
| 字段 | 类型 | 说明 | 必填项 | 
|---|---|---|---|
| rel | String | 如按关联模型的字段排序,则填写关联模型名称 | 否 | 
| column | String | 字段名称 | 否 | 
| option | String | 排序方式, desc, asc, 默认为 asc | 否 | 
使用 Query DSL 查询 
Query DSL 可以在数据流中使用,一般用于数据分析统计等更为复杂的场景。
对数据表 service (见下表)分析, 统计各行业最高分。
| id | industries | city | score | created_at | updated_at | 
|---|---|---|---|---|---|
| 1 | ["旅游", "教育"] | 北京 | 99 | 2021-10-03 13:40:52 | NULL | 
| 2 | ["旅游", "教育"] | 上海 | 68 | 2021-10-03 13:40:52 | NULL | 
| 3 | ["旅游", "教育"] | 北京 | 92 | 2021-10-03 13:40:52 | NULL | 
| 4 | ["旅游", "教育"] | 上海 | 87 | 2021-10-03 13:40:52 | NULL | 
| 5 | ["旅游", "教育"] | 北京 | 71 | 2021-10-03 13:46:06 | NULL | 
Query DSL 示例:
JSON 描述:
json
{
  "comment": "统计各行业最高分",
  "select": ["industries@", "city", ":MAX(score) as high_score"],
  "from": "service",
  "wheres": [
    { ":created_at": "创建时间", ">=": "2021-01-01" },
    { ":created_at": "创建时间", "<=": "{'2021-12-31'}" },
    { ":updated_at": "更新时间", "is": "null" },
    {
      "wheres": [
        { ":type": "类型", "=": 1 },
        { "or:type": "或类型", "=": 2 }
      ]
    }
  ],
  "orders": "high_score desc",
  "limit": 100,
  "groups": ["industries@", "city"]
}引擎解析后的 SQL语句 为 (MySQL 8):
sql
SELECT `@industries`.`industries`,`city`, MAX(`score`) AS `high_score`
FROM `service`
JOIN JSON_TABLE(`service`.`industries`, '$[*]' columns (`industries` varchar(50) path '$') ) as `@industries`
WHERE `created_at` >= '2021-01-01'
  AND `created_at` <= '2021-12-31'
  AND `updated_at` IS NULL
  AND ( `type` = 1 OR `type` = 2)
GROUP BY `@industries`.`industries`, `city`
ORDER BY `high_score` DESC返回结果:
| industries | city | high_score | 
|---|---|---|
| 旅游 | 北京 | 99 | 
| 教育 | 北京 | 99 | 
| 旅游 | 上海 | 87 | 
| 教育 | 上海 | 87 | 
在 Flow 中使用 
在数据流中,可以使用 {{$in}} 或 ?:$in 接收参数, {{$res}} 或 ?:$res 引用节点查询结果。
提示:在数据流中通过 {{$xxx}} 或 ?:$xxx 使用变量写法等效。
使用模型处理器 
json
{
  "label": "查询最新数据",
  "version": "1.0.0",
  "description": "查询系统最新数据",
  "nodes": [
    {
      "name": "宠物",
      "process": "models.pet.Get",
      "args": [
        {
          "select": ["id", "name", "kind", "created_at"],
          "wheres": [{ "column": "kind", "value": "{{$in.0}}" }],
          "orders": [{ "column": "created_at", "option": "desc" }],
          "limit": 10
        }
      ]
    }
  ],
  "output": "{{$res.宠物}}"
}使用 Query DSL 
json
{
  "label": "查询最新数据",
  "version": "1.0.0",
  "description": "查询系统最新数据",
  "nodes": [
    {
      "name": "宠物",
      "engine": "xiang",
      "query": {
        "select": ["id", "name", "kind", "created_at"],
        "from": "$pet",
        "wheres": [{ ":kind": "类型", "=": "?:$in.0" }],
        "orders": "created_at desc",
        "limit": 10
      }
    }
  ],
  "output": "{{$res.宠物}}"
}在 Script 中使用 
javascript
function test(id) {
  var query = new Query();
  var data = query.Get({
    name: '宠物',
    engine: 'xiang',
    query: {
      select: ['id', 'name', 'kind', 'created_at'],
      from: '$pet',
      wheres: [{ ':kind': '类型', '=': id }],
      orders: 'created_at desc',
      limit: 10
    }
  });
}在数据表格中使用 
在数据表格中,可以使用 filter 传递查询参数。查询参数通过 URL Query String 传递给数据表格接口。
指定查询参数名称:
json
{
  "name": "宠物",
  "version": "1.0.0",
  "decription": "宠物管理表格",
  "bind": { "model": "pet" },
  "apis": {},
  "columns": {},
  "filters": {
    "关键词": {
      "label": "关键词",
      "bind": "where.name.match",
      "input": { "type": "input", "props": { "placeholder": "请输入关键词" } }
    }
  },
  "list": {
      "filters": ["关键词"],
      ...
  },
  "edit": {}
}在点击界面搜索按钮时,系统向表格 search API 请求数据,并传入 bind 中声明的参数名和用户填写数值:
bash
GET /api/xiang/table/pet?where.name.match=xxx