| name | dataset-query |
| description | Query-first dataset access with @domoinc/query including filters, grouping, date grains, and performance constraints. |
@domoinc/query - Data Query Builder
CRITICAL: Use the Query API (via @domoinc/query) for all dataset queries in Domo apps. This is essential because:
-
Page Filter Integration - The Query API automatically respects page-level filters when your app is embedded in a Domo dashboard. This is key for apps that need to respond to dashboard filter changes.
-
Performance - The Query API allows you to query only the data you need at the aggregation level required, rather than fetching entire datasets. This is critical for performance, especially with large datasets.
-
Server-Side Processing - Aggregations and filtering happen on Domo's servers, reducing data transfer and client-side processing.
Non-Query data access: If your app bypasses @domoinc/query (e.g., Code Engine calls, raw SQL via SqlClient, or direct /data/v1/ fetches without query parameters), page filters are NOT applied automatically. You must register domo.onFiltersUpdated (see domo-js) and pass filter values as parameters to your data source manually. The same applies to App Studio variables — use domo.onVariablesUpdated to receive variable changes and incorporate them into your queries.
The Query library provides a chainable API for building complex data queries. It constructs URLs that work with domo.get() and the /data/v1/ endpoint.
npm/yarn:
yarn add @domoinc/query
import Query from '@domoinc/query';
CDN (Vanilla JavaScript):
<script src="https://cdn.jsdelivr.net/npm/@domoinc/query@3.0.0/dist/main.min.js"></script>
const data = await new Query()
.select(['region', 'sales'])
.fetch('sales-dataset');
Basic Usage
const data = await new Query()
.select(['region', 'sales', 'date'])
.fetch('sales-dataset');
const filtered = await new Query()
.select(['region', 'product', 'sales'])
.where('sales').greaterThan(1000)
.where('region').in(['North', 'South'])
.fetch('sales-dataset');
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
new Query().select(['col1', 'col2', 'col3'])
new Query().fetch('dataset')
Where Filters
All filter methods return the Query for chaining.
.where('amount').lessThan(100)
.where('amount').lessThanOrEqual(100)
.where('amount').greaterThan(100)
.where('amount').greaterThanOrEqual(100)
.where('amount').equals(100)
.where('amount').notEquals(100)
.where('amount').between(100, 500)
.where('name').contains('test')
.where('name').notContains('test')
.where('category').in(['A', 'B', 'C'])
.where('status').notIn(['deleted', 'archived'])
.where('amount').greaterThan(100)
.where('status').equals('active')
.where('region').in(['North', 'South'])
Group By
.groupBy('region')
.groupBy('region')
.groupBy('product')
.groupBy('region', {
sales: 'sum',
quantity: 'avg',
price: 'max',
orders: 'count',
skus: 'unique'
})
.groupBy('region')
.groupBy('product', { sales: 'sum', orders: 'count' })
Aggregation Functions:
'count' - Count rows
'sum' - Sum values
'avg' - Average values
'min' - Minimum value
'max' - Maximum value
'unique' - Count distinct values
CRITICAL - Aggregation Key Syntax
Aggregation keys MUST be the actual field names from your dataset, NOT custom aliases.
The key in the aggregation object determines the output property name. If you use an alias that doesn't match a field, you'll get [object Object] errors.
.groupBy('region', {
Sales_Amount: 'sum',
Order_Qty: 'count'
})
.groupBy('region', {
totalSales: 'sum',
orderCount: 'count'
})
const data = await new Query()
.groupBy('region', { Sales_Amount: 'sum' })
.fetch('sales');
const renamed = data.map(row => ({
region: row.region,
totalSales: row.Sales_Amount
}));
Order By
.orderBy('sales', 'descending')
.orderBy('date', 'ascending')
.orderBy('region', 'ascending')
.orderBy('sales', 'descending')
Limit and Offset
.limit(100)
.offset(50)
const page = 2;
const pageSize = 25;
new Query()
.limit(pageSize)
.offset((page - 1) * pageSize)
.fetch('dataset');
Date Operations
dateGrain - Group by Date Period
.dateGrain('order_date', 'month')
.dateGrain('order_date', 'month', { Revenue: 'sum', Order_Count: 'count' })
.dateGrain('date', 'day')
.dateGrain('date', 'week')
.dateGrain('date', 'month')
.dateGrain('date', 'quarter')
.dateGrain('date', 'year')
CRITICAL: The third parameter (aggregations) follows the same rules as groupBy - keys must match actual dataset field names:
.dateGrain('order_date', 'month', { Sales_Amount: 'sum' })
.dateGrain('order_date', 'month', { totalSales: 'sum' })
periodToDate - YTD, MTD, QTD, etc.
.periodToDate('date', 'year')
.periodToDate('date', 'month')
.periodToDate('date', 'quarter')
const ytdSales = await new Query()
.select(['date', 'sales'])
.periodToDate('date', 'year')
.groupBy({ sales: 'sum' })
.fetch('sales');
previousPeriod - Last Period Comparison
.previousPeriod('date', 'year')
.previousPeriod('date', 'month')
.previousPeriod('date', 'quarter')
rollingPeriod - Rolling Windows
.rollingPeriod('date', 'days', 30)
.rollingPeriod('date', 'weeks', 12)
.rollingPeriod('date', 'months', 6)
.rollingPeriod('date', 'quarters', 4)
.rollingPeriod('date', 'years', 3)
Additional Options
.useFiscalCalendar(true)
.useBeastModes()
Complete Examples
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');
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');
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');