关于 dataset-query
面向 Domo 应用开发者的 JavaScript 查询构建库,可链式创建数据集查询并调用 Domo 数据接口。它支持筛选、聚合和日期周期操作,并自动遵循嵌入式仪表板的页面筛选器。
主要功能
- 01链式构建数据集查询
- 02选择列并添加条件筛选
- 03分组、聚合与排序
- 04日期粒度及周期查询
- 05限制行数与分页偏移
适用场景
- 01按仪表板页面筛选器查询数据
- 02只获取所需列和聚合结果
- 03按日期周期汇总指标
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ stahura/ domo-ai-vibe-rules --skill dataset-query安装后在 Claude Code 中输入/dataset-query确认已加载。
详细介绍
@domoinc/query - 数据查询构建器
关键: 在 Domo 应用中,所有数据集查询都应使用 Query API(通过 @domoinc/query)。这一点至关重要,原因如下:
-
页面筛选器集成 - 当你的应用嵌入到 Domo 仪表板中时,Query API 会自动遵循页面级筛选器。这对于需要响应仪表板筛选器变化的应用来说至关重要。
-
性能 - Query API 允许你仅在所需的聚合级别查询所需的数据,而不是获取整个数据集。这对性能至关重要,尤其是在处理大型数据集时。
-
服务端处理 - 聚合和筛选在 Domo 的服务器上进行,减少了数据传输和客户端处理。
非 Query 数据访问:如果你的应用绕过了 @domoinc/query(例如,Code Engine 调用、通过 SqlClient 的原始 SQL,或直接使用不带查询参数的 /data/v1/ 请求),页面筛选器不会自动应用。你必须注册 domo.onFiltersUpdated(参见 domo-js),并手动将筛选器值作为参数传递给你的数据源。App Studio 变量同样如此——使用 domo.onVariablesUpdated 接收变量变化,并将其纳入你的查询中。
Query 库提供了一套可链式调用的 API,用于构建复杂的数据查询。它构建的 URL 可与 domo.get() 和 /data/v1/ 端点配合使用。
npm/yarn:
yarn add @domoinc/query
import Query from '@domoinc/query';
CDN(原生 JavaScript):
<script src="https://cdn.jsdelivr.net/npm/@domoinc/[email protected]/dist/main.min.js"></script>
// Query is available globally after CDN script loads
const data = await new Query()
.select(['region', 'sales'])
.fetch('sales-dataset');
基本用法
// Simple query
const data = await new Query()
.select(['region', 'sales', 'date'])
.fetch('sales-dataset');
// With filtering
const filtered = await new Query()
.select(['region', 'product', 'sales'])
.where('sales').greaterThan(1000)
.where('region').in(['North', 'South'])
.fetch('sales-dataset');
// With grouping and aggregation
const summary = await new Query()
.select(['region', 'sales', 'quantity'])
.groupBy('region')
.groupBy({ sales: 'sum', quantity: 'avg' })
.orderBy('sales', 'descending')
.limit(10)
.fetch('sales-dataset');
Select
// Select specific columns
new Query().select(['col1', 'col2', 'col3'])
// Select all (omit select)
new Query().fetch('dataset')
Where 筛选器
所有筛选器方法都返回 Query 以支持链式调用。
// Comparison filters
.where('amount').lessThan(100) // .lt(100)
.where('amount').lessThanOrEqual(100) // .lte(100)
.where('amount').greaterThan(100) // .gt(100)
.where('amount').greaterThanOrEqual(100) // .gte(100)
.where('amount').equals(100)
.where('amount').notEquals(100)
.where('amount').between(100, 500)
// String filters
.where('name').contains('test')
.where('name').notContains('test')
// List filters
.where('category').in(['A', 'B', 'C'])
.where('status').notIn(['deleted', 'archived'])
// Multiple conditions (AND)
.where('amount').greaterThan(100)
.where('status').equals('active')
.where('region').in(['North', 'South'])
Group By
// Group by single column
.groupBy('region')
// Group by multiple columns
.groupBy('region')
.groupBy('product')
// Group by column with aggregations (second parameter)
.groupBy('region', {
sales: 'sum',
quantity: 'avg',
price: 'max',
orders: 'count',
skus: 'unique'
})
// Multiple groupBy calls
.groupBy('region')
.groupBy('product', { sales: 'sum', orders: 'count' })
聚合函数:
'count'- 统计行数'sum'- 求和'avg'- 求平均值'min'- 最小值'max'- 最大值'unique'- 统计去重后的值
关键 - 聚合键语法
聚合键必须是数据集中的实际字段名,而不是自定义别名。
聚合对象中的键决定了输出属性的名称。如果你使用的别名与字段不匹配,将会出现 [object Object] 错误。
// ✅ CORRECT - Keys match actual field names
// If your dataset has fields: 'Sales_Amount', 'Order_Qty'
.groupBy('region', {
Sales_Amount: 'sum', // Key matches dataset field
Order_Qty: 'count' // Key matches dataset field
})
// Results: [{ region: 'North', Sales_Amount: 50000, Order_Qty: 150 }]
// ❌ WRONG - Custom aliases as keys cause [object Object] errors
.groupBy('region', {
totalSales: 'sum', // 'totalSales' is not a field name!
orderCount: 'count' // 'orderCount' is not a field name!
})
// ✅ If you need custom names, rename AFTER fetching:
const data = await new Query()
.groupBy('region', { Sales_Amount: 'sum' })
.fetch('sales');
const renamed = data.map(row => ({
region: row.region,
totalSales: row.Sales_Amount // Rename here
}));
Order By
.orderBy('sales', 'descending') // or 'desc'
.orderBy('date', 'ascending') // or 'asc'
// Multiple sort columns
.orderBy('region', 'ascending')
.orderBy('sales', 'descending')
Limit 和 Offset
.limit(100) // Max rows
.offset(50) // Skip rows (for pagination)
// Pagination example
const page = 2;
const pageSize = 25;
new Query()
.limit(pageSize)
.offset((page - 1) * pageSize)
.fetch('dataset');
日期操作
dateGrain - 按日期周期分组
// Group by month
.dateGrain('order_date', 'month')
// Group by month with aggregations
// NOTE: Aggregation keys must be actual field names!
.dateGrain('order_date', 'month', { Revenue: 'sum', Order_Count: 'count' })
// Available grains: 'day', 'week', 'month', 'quarter', 'year'
.dateGrain('date', 'day')
.dateGrain('date', 'week')
.dateGrain('date', 'month')
.dateGrain('date', 'quarter')
.dateGrain('date', 'year')
关键: 第三个参数(聚合)遵循与 groupBy 相同的规则——键必须与数据集中的实际字段名匹配:
// ✅ CORRECT - field names as keys
.dateGrain('order_date', 'month', { Sales_Amount: 'sum' })
// ❌ WRONG - custom aliases cause errors
.dateGrain('order_date', 'month', { totalSales: 'sum' })
periodToDate - YTD、MTD、QTD 等
// Year to date
.periodToDate('date', 'year')
// Month to date
.periodToDate('date', 'month')
// Quarter to date
.periodToDate('date', 'quarter')
// Full example
const ytdSales = await new Query()
.select(['date', 'sales'])
.periodToDate('date', 'year')
.groupBy({ sales: 'sum' })
.fetch('sales');
previousPeriod - 上一周期对比
// Last year
.previousPeriod('date', 'year')
// Last month
.previousPeriod('date', 'month')
// Last quarter
.previousPeriod('date', 'quarter')
rollingPeriod - 滚动窗口
// Last 30 days
.rollingPeriod('date', 'days', 30)
// Last 12 weeks
.rollingPeriod('date', 'weeks', 12)
// Last 6 months
.rollingPeriod('date', 'months', 6)
// Last 4 quarters
.rollingPeriod('date', 'quarters', 4)
// Last 3 years
.rollingPeriod('date', 'years', 3)
其他选项
// Use fiscal calendar
.useFiscalCalendar(true)
// Enable beast modes (calculated fields)
.useBeastModes()
// ⚠️ WARNING: .aggregate() does NOT work in practice
// It causes error: "DA0057: An alias list was provided but it could not be parsed"
// Use .groupBy() with a grouping column instead, or .select() + client-side aggregation
// ❌ .aggregate({ total: 'sum', average: 'avg' }) // DOES NOT WORK
完整示例
// Sales dashboard query
const salesByRegion = await new Query()
.select(['region', 'product_category', 'sales', 'quantity', 'date'])
.where('sales').greaterThan(0)
.where('date').greaterThanOrEqual('2024-01-01')
.dateGrain('date', 'month')
.groupBy('region')
.groupBy('product_category')
.groupBy({ sales: 'sum', quantity: 'sum', orders: 'count' })
.orderBy('sales', 'descending')
.limit(100)
.fetch('sales-dataset');
// YoY comparison
const thisYear = await new Query()
.select(['month', 'revenue'])
.periodToDate('date', 'year')
.dateGrain('date', 'month', { revenue: 'sum' })
.fetch('revenue');
const lastYear = await new Query()
.select(['month', 'revenue'])
.previousPeriod('date', 'year')
.dateGrain('date', 'month', { revenue: 'sum' })
.fetch('revenue');
// Trend analysis - last 90 days
const trend = await new Query()
.select(['date', 'sales', 'orders'])
.rollingPeriod('date', 'days', 90)
.dateGrain('date', 'day', { sales: 'sum', orders: 'count' })
.orderBy('date', 'ascending')
.fetch('sales');