Skip to content

Commit c4d22bc

Browse files
morgan-at-cubemarianore-muttdata
authored andcommitted
docs: Update passing-dynamic-parameters-in-a-query.mdx (cube-js#9384)
* Update passing-dynamic-parameters-in-a-query.mdx FILTER_PARAMS should always be used in this use case to avoid a massive cross join. I also added a simpler code snippet that is easier to adapt to any use case rather than the original verbose version. * Update passing-dynamic-parameters-in-a-query.mdx Fix missing quote
1 parent c3ea742 commit c4d22bc

File tree

1 file changed

+58
-12
lines changed

1 file changed

+58
-12
lines changed

docs/pages/guides/recipes/data-modeling/passing-dynamic-parameters-in-a-query.mdx

Lines changed: 58 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,17 @@ filter. The trick is to get the value of the city from the user and use it in
1616
the calculation. In the recipe below, we can learn how to join the data table
1717
with itself and reshape the dataset!
1818

19+
<WarningBox>
20+
21+
This pattern only allows users to choose from values that already exist in the data set. Rather than injecting arbitrary user input into the query, this method involves filtering the data based on the user's input and utilizing a single value result in a calculation.
22+
23+
</WarningBox>
24+
1925
## Data modeling
2026

21-
Essentially what we will be doing is cross joining all city values with the rows in the data table.
22-
This will duplicate each row for every city in the dataset. Then, we will require the user
23-
to choose a city to filter on, and this will bring us back to our original number of rows. What this
24-
gives us is a new column in the dataset with the value that the user chose, which we can reference in our metrics.
27+
Essentially what we will be doing is allowing the user to select a specific city value, then cross joining that value with the rows in the data table.
28+
This will maintain the orginal number of rows in the dataset while adding a new column that has the value that the user chose.
29+
This will allow us to use that value in our calculations.
2530
In this case, we will use that value to filter a single metric so that we can compare that metric with the whole population.
2631

2732
Let's explore the `users` cube data that contains various information about
@@ -35,13 +40,16 @@ users, including city and gender:
3540
| ... | ... | ... | ... |
3641

3742
To calculate the ratio between the number of women in a particular city and the
38-
total number of people in the country, we need to define three measures. One of
39-
them can receive the city value from the filter in a query. Cube will apply this
40-
filter via the `WHERE` clause to the dataset. So, we need to reshape the dataset
41-
so that applying this filter wouldn’t affect the calculations. In this use case,
42-
we can join the data table with itself to multiply the `city` column — applying
43-
the filter would remove the multiplication while still allowing to access the
44-
filter value:
43+
total number of people in the country, we need to define three measures, one of
44+
which uses the city value that the user chose.
45+
46+
In order to prevent filtering the whole dataset with the user-selected value,
47+
we will need to define a new dimension that, when filtered on, only filters a specific part of the query.
48+
We will use this new filter field along with the [`FILTER_PARAMS`][ref-filter-params]
49+
parameter in the sql of the cube. This will allow us to apply to the filter to a subquery
50+
rather than the whole query so that it doesn't affect other calculations.
51+
In this use case, we can join the data table with itself to create a new city_filter
52+
column with a single value that the user chose so that we can use it in other calculations.
4553

4654
<CodeTabs>
4755

@@ -59,6 +67,7 @@ cubes:
5967
cities AS (
6068
SELECT city
6169
FROM data
70+
WHERE {FILTER_PARAMS.users.city.filter('city')}
6271
),
6372
grouped AS (
6473
SELECT
@@ -77,7 +86,7 @@ cubes:
7786
sql: id
7887
type: count
7988
filters:
80-
- sql: "gender = 'female' and city = city_filter"
89+
- sql: "gender = 'female'"
8190

8291
- name: number_of_people_of_any_gender_in_the_city:
8392
sql: id
@@ -112,6 +121,7 @@ cube(`users`, {
112121
cities AS (
113122
SELECT city
114123
FROM data
124+
WHERE ${FILTER_PARAMS.users.city.filter('city')}
115125
),
116126
117127
grouped AS (
@@ -161,6 +171,40 @@ cube(`users`, {
161171

162172
</CodeTabs>
163173

174+
The above code shows very clearly what is happening, but it is even simplier to define the sql parameter in the following way:
175+
176+
<CodeTabs>
177+
178+
```yaml
179+
cubes:
180+
- name: users
181+
sql: >
182+
WITH
183+
city AS (
184+
SELECT DISTINCT city AS city_filter
185+
FROM public.users
186+
WHERE {FILTER_PARAMS.users.city.filter('city')}
187+
)
188+
SELECT city.city_filter, users.*
189+
FROM city, public.users
190+
```
191+
192+
```javascript
193+
cube(`users`, {
194+
sql: `
195+
WITH
196+
city AS (
197+
SELECT DISTINCT city AS city_filter
198+
FROM public.users
199+
WHERE {FILTER_PARAMS.users.city.filter('city')}
200+
)
201+
SELECT city.city_filter, users.*
202+
FROM city, public.users
203+
`,
204+
```
205+
206+
</CodeTabs>
207+
164208
## Query
165209
166210
To get the ratio result depending on the city, we need to pass the value via a
@@ -204,3 +248,5 @@ Please feel free to check out the
204248
[full source code](https://github.com/cube-js/cube/tree/master/examples/recipes/passing-dynamic-parameters-in-query)
205249
or run it with the `docker-compose up` command. You'll see the result, including
206250
queried data, in the console.
251+
252+
[ref-filter-params]: /reference/data-model/context-variables#filter_params

0 commit comments

Comments
 (0)