尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
Actual 的 ActualQL 查询语言完全指南:从基础查询到拆分交易与操作符实战
Actual 的 ActualQL 查询语言完全指南从基础查询到拆分交易与操作符实战【免费下载链接】actualA local-first personal finance app项目地址: https://gitcode.com/GitHub_Trending/ac/actualActualQL 是 Actual本地优先的个人财务管理应用在 0.0.129 版本中引入的查询语言用于替代此前行为固化在服务端的filterTransactions方法让用户能够以声明式语法自由查询交易、排序、筛选并聚合数据。本文以 ActualQL 官方文档为主线结合仓库源码查询构建器、编译器与测试用例逐层展开帮助你掌握构建查询、执行查询、操作符筛选以及拆分交易split transactions处理的完整实战方案。一、ActualQL 是什么从filterTransactions到可组合查询在 ActualQL 出现之前Actual 仅提供filterTransactions这类内置方法搜索交易但其行为完全被硬编码在后端你无法自定义排序规则、无法针对特定字段精确搜索、也无法直接对金额求和。ActualQL 提供了一个轻量级的查询语法把上述能力全部开放给调用方。一个最基础的 ActualQL 查询长这样q(transactions) .filter({ category.name: Food, date: 2021-02-20, }) .select([id, date, amount]);该查询会返回2021-02-20当天、类别为Food的所有交易的id、date、amount字段。值得强调的是Actual 自身的大部分功能都在使用 ActualQL文档原话为 Most of Actual uses ActualQL因此通过 API 你能访问到与 Actual 应用内部完全一致的查询能力而不是一套受限的简化接口。二、快速上手构建查询与执行查询ActualQL 的用法分为两步先用q()构建查询对象再用runQuery()执行它。let { q, runQuery } require(actual-app/api); let { data } await runQuery(q(transactions).select(*));执行结果是一个对象其中data属性保存查询结果。上面的例子中data是系统中全部交易的数组。从源码看执行链路在 packages/api/methods.ts 中可以看到runQuery与aqlQuery都是把查询序列化后通过消息通道发送给核心引擎export function runQuery(query: Query) { return send(api/query, { query: query.serialize() }); } export function aqlQuery(query: Query) { return send(api/query, { query: query.serialize() }); }注意当前版本中runQuery已被标记为deprecated源码注释建议改用aqlQueryPlease useaqlQueryinstead. This function will be removed in a future release.。文档示例仍以runQuery演示两者行为一致新代码建议直接使用aqlQuery。在引擎侧请求最终进入 packages/loot-core/src/server/aql/index.ts 的aqlQuery它将查询状态交给编译与执行管线compileAndRunAqlQuery结合 schema 与执行器schemaExecutors完成从查询对象到结果集的转换。q构建器与 Query 类q是一个工厂函数返回Query实例其完整定义位于 packages/loot-core/src/shared/query.ts 与 API 侧的 packages/api/app/query.ts。Query采用不可变链式风格每次调用都返回携带新状态的新实例。除了文档提到的filter、select、options它还提供了大量可用方法方法作用filter(expr)追加筛选条件unfilter(keys?)按字段名移除指定筛选条件不传参数则清空全部select(exprs)指定返回字段支持*或字段数组calculate(expr)执行聚合计算如求和结果作为result返回groupBy(exprs)按表达式分组orderBy(exprs)排序limit(n)/offset(n)分页options(opts)设置表级选项如拆分交易处理raw()原始模式跳过字段映射withDead()包含已删除tombstone记录withoutValidatedRefs()关闭引用字段校验serialize()序列化为可传输的查询状态在 packages/api/app/query.ts 可以看到QueryState的默认初始化tableOptions、filterExpressions、selectExpressions、groupExpressions、orderExpressions默认为空validateRefs默认为true即默认会校验字段引用是否存在于 schema 中。三、搜索交易filter 与操作符详解调用filter即对查询施加条件只有满足所有条件的记录才会被返回。filter 对象的键是字段名值是条件默认执行等于比较也支持传入各种操作符。基础示例多字段 比较操作符q(transactions) .filter({ category.name: Food, date: { $gte: 2021-01-01 }, }) .select(*);date: { $gte: 2021-01-01 }表示返回2021-01-01及之后的交易。完整操作符列表文档明确列出的可用操作符为$eq、$lt、$lte、$gt、$gte、$ne、$oneof、$regex、$like、$notlike。操作符含义$eq等于默认$lt/$lte小于 / 小于等于$gt/$gte大于 / 大于等于$ne不等于$oneof值属于给定集合中的任意一个$regex正则表达式匹配$like模糊匹配SQL LIKE 风格$notlike模糊不匹配在编译器 packages/loot-core/src/server/aql/compiler.ts 中可以看到这些操作符的底层 SQL 实现$oneof被编译为IN (...)子句且会自动对 id 集合去重$like使用UNICODE_LIKENORMALISE实现大小写无关的模糊匹配模式串同样会被规范化$regex在编译器源码中对应分支名为$regexp编译为REGEXP(...)$notlike编译为NOT UNICODE_LIKE(...) OR field IS NULL未识别的操作符会抛出CompileError: Unknown operator。这意味着文档描述之外你还拥有正则与 LIKE 通配符等灵活的字符串匹配能力。数组条件自动合并为 AND如果给某个字段传入数组多个条件会被自动用$and组合q(transactions) .filter({ date: [{ $gte: 2021-01-01 }, { $lte: 2021-12-31 }], }) .select(*);这等价于显式使用$andq(transactions) .filter({ $and: [{ date: { $gte: 2021-01-01 } }, { date: { $lte: 2021-12-31 } }], }) .select(*);两条查询都限定交易日期在2021-01-01与2021-12-31之间。$and 与 $or组合多条独立条件$and与$or接收条件数组并合并多个条件。例如获取多个日期的交易q(transactions) .filter({ $or: [{ date: 2021-01-01 }, { date: 2021-01-02 }], }) .select(*);上述查询会返回2021-01-01或2021-01-02的交易。字段与点路径dotted path文档示例中的category.name是一种点路径字段引用它沿外键关系穿透到关联表。在 schema 定义 packages/loot-core/src/server/aql/schema/index.ts 中transactions表的category字段被声明为f(id, { ref: categories })因此可以直接用category.name引用类别的名称字段。以transactions表为例其可用字段包括源码可见于 schema/index.tsid、account、category、amount整数单位分、payee、notes、date、imported_id、error、imported_payee、starting_balance_flag、transfer_id、sort_order、cleared、reconciled、tombstone、schedule、raw_synced_data。日期类字段使用YYYY-MM-DD字符串格式。四、处理拆分交易Split Transactions拆分交易会让聚合与选择变得复杂当对交易金额求和时是统计所有子交易还是只用顶层交易选择交易时你想要哪些记录transactions表为此提供了两种不同的数据接口通过options传入splits选项进行配置q(transactions).select(*).options({ splits: inline });inline默认值inline是默认行为不会返回拆分交易的 parent 交易只返回子交易结果是一个扁平数组。这样默认求和时就自然忽略了 parent 交易避免重复统计金额。groupedgrouped总是返回完整的拆分交易parent 全部子交易无论命中筛选条件的是哪一部分。返回的数据是分组的交易带有一个subtransactions属性列出其子交易。all与none文档脚注还提到第三种选项all以扁平列表同时返回交易与子交易仅在需要做高级处理时才用。而从源码 packages/loot-core/src/server/aql/schema/executors.ts 看合法的取值实际有四种function isValidSplitsOption(splits: string): splits is SplitsOption { return [all, inline, none, grouped].includes(splits); }其中none只返回 parent 交易不含子交易。若传入非法值执行器会抛出Invalid splits option for transactions错误见 executors.ts。源码级行为差异executors.ts 顶部注释给出了一个极具说明性的对比// q(transactions).select({ $count: id }) // q(transactions, { splits: grouped }).select({ $count: id }) // // The first will return the count of non-split and child // transactions, and the second will return the count of all parent // (or non-split) transactions即默认模式下计数包含普通交易与子交易grouped模式下计数只统计 parent或非拆分交易。对应的行为测试覆盖在 packages/loot-core/src/server/aql/schema/executors.test.ts 中包括splits: inline只返回非 parent 交易、splits: none只返回 parent、以及splits: grouped下的聚合查询等场景。此外subtransactions是一个特殊字段只有当表使用splits: grouped选项时才存在见 schema/index.ts 的注释。选择inline还是grouped本质上是选择面向金额汇总还是面向完整结构的数据视角——这四种选项给了你处理拆分交易的完全控制权。五、底层原理ActualQL 如何编译为 SQL理解 ActualQL 的工作机制有助于你写出更高效的查询。其核心管线位于 packages/loot-core/src/server/aql 目录schemaschema/index.ts定义各表字段、类型、引用关系以及表视图tableViews的构建逻辑——在 schema/index.ts 中可以看到视图构建时会根据tableOptions.splits决定如何拼接拆分交易数据默认splits为inlinecompilercompiler.ts将查询状态filter、select、group、order 表达式编译为 SQL 片段操作符在这里转换为对应的 SQL 运算符executorsschema/executors.ts负责执行编译结果其中execTransactions根据splits选项分发到execTransactionsBasic处理all/inline/none或execTransactionsGrouped处理grouped对结果按 parent 分组并附加subtransactionsexecexec.ts调用编译与执行入口compileAndRunAqlQuery/runCompiledAqlQuery并在 aql/index.ts 中对外暴露aqlQuery与aqlCompiledQuery。也就是说你写的q(transactions).filter({...}).select(...)会被编译成 SQL 执行$oneof变成IN、$like变成UNICODE_LIKE、$or变成OR分支等最终把 SQLite 的查询能力完整暴露给上层调用方。六、总结与延伸阅读ActualQL 把 Actual 应用内部的查询能力完整开放给了外部调用者通过q构建器与链式方法组合筛选、选择、排序、分组、聚合与分页通过 filter 操作符实现精确到字段的比较、正则与模糊匹配通过splits选项精确控制拆分交易的返回形态。无论你是在做账单导入脚本、财务报表还是数据迁移都可以复用 Actual 应用本身同款的能力。延伸阅读Transaction 字段参考拆分交易结构说明查看transactions表各字段的完整定义与拆分交易创建规则API 总览了解runQuery/aqlQuery之外的全部 API 方法API 查询构建器实现Query类各链式方法的源码核心查询引擎aqlQuery编译与执行入口拆分交易执行器测试splits各选项行为的具体测试用例。【免费下载链接】actualA local-first personal finance app项目地址: https://gitcode.com/GitHub_Trending/ac/actual创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED

相关推荐

嵌入式面试避坑指南:从C语言到RTOS的核心能力解析

嵌入式面试避坑指南:从C语言到RTOS的核心能力解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📅 2026/9/11 22:01:32
HTML table标签属性全解析:从过时属性到现代CSS替代方案

HTML table标签属性全解析:从过时属性到现代CSS替代方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📅 2026/9/11 21:56:30
为什么劝你做 Agent 先手搓一遍:框架的抽象税,是生产环境最贵的隐性负债

为什么劝你做 Agent 先手搓一遍:框架的抽象税,是生产环境最贵的隐性负债

如果你问我:现在做一个 Agent,第一反应应该用什么?我的答案可能和大多数人不一样——先别急着上 LangChain,自己手写一遍。 不是框架不好用,而是很多人在真正吃过苦头之前,压根没意识到框架到底替你做了什么…

📅 2026/9/11 21:56:30
MORE NEWS

更多资讯

📰

Gopeed 桌面多窗口 Capability RPC 架构解析:主窗口与子窗口的通信契约设计与实现

Gopeed 桌面多窗口 Capability RPC 架构解析:主窗口与子窗口的通信契约设计与实现 【免费下载链接】gopeed A fast, modern download manager for HTTP, BitTorrent, Magnet, and ed2k. Cross-platform, built with Golang and Flutter. 项目地址: https://gitco…

📰

数据驱动的库存路径优化:预测与优化一体化实践

1. 项目背景与核心挑战库存路径优化(Inventory Routing Problem, IRP)一直是供应链管理中的经典难题。传统方法通常将预测和优化作为两个独立阶段处理,这种割裂式处理在面对实时动态变化的物流需求时往往捉襟见肘。我们团队在服务某快消品龙头…

📰

RK3588边缘AI设备OOM守护:systemd内存韧性配置实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

Nx 21.3 迁移实战:自动替换 Jest v30 移除的 Matcher 别名

Nx 21.3 迁移实战:自动替换 Jest v30 移除的 Matcher 别名 【免费下载链接】nx The Monorepo Platform that amplifies both developers and AI agents. Nx optimizes your builds, scales your CI, and fixes failed PRs automatically. Ship in half the time. …

📰

2026视觉标定板实测:自动化程度对科研误差的影响分析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📰

Flink Web UI 核心功能与生产环境实战指南

1. Flink Web UI 完全指南:从入门到精通作为Apache Flink的核心管理界面,Web UI是每个Flink开发者必须掌握的运维工具。我在实际生产环境中使用Flink处理日均PB级数据时,发现90%的集群问题都可以通过Web UI快速定位。这个可视化控制台不仅提供…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬