From 7b2e3e8cdf28b048a812ed833645e988024aae67 Mon Sep 17 00:00:00 2001 From: Igor Lukanin Date: Fri, 21 Apr 2023 20:15:12 +0200 Subject: [PATCH 1/8] Update the joins page --- docs/content/Schema/Reference/joins.mdx | 272 +++++++++++++----------- 1 file changed, 146 insertions(+), 126 deletions(-) diff --git a/docs/content/Schema/Reference/joins.mdx b/docs/content/Schema/Reference/joins.mdx index 49b3bae3648bc..e0cf205c7488a 100644 --- a/docs/content/Schema/Reference/joins.mdx +++ b/docs/content/Schema/Reference/joins.mdx @@ -20,13 +20,7 @@ time. cube('MyCube', { joins: { TargetCubeName: { - relationship: - `belongsTo` || - `hasMany` || - `hasOne` || - `belongs_to` || - `has_many` || - `has_one`, + relationship: `one_to_one` || `one_to_many` || `many_to_one`, sql: `SQL ON clause`, }, }, @@ -38,7 +32,7 @@ cubes: - name: MyCube joins: - name: TargetCubeName - relationship: belongsTo || hasMany || hasOne + relationship: one_to_one || one_to_many || many_to_one sql: SQL ON clause ``` @@ -63,18 +57,18 @@ practice to have a separate cube for such an operation. ## Naming -The name of a join should match the [name of the external -cube][ref-schema-cube-naming]. For example when a `Products` cube is being -joined on to an `Orders` cube, we would define the join as follows: +The name of a join should match the [name of the joined +cube][ref-schema-cube-naming]. For example when a `products` cube is being +joined to an `orders` cube, the join would be defined as follows: ```javascript -cube('Orders', { +cube(`orders`, { joins: { - Products: { - relationship: `belongsTo`, - sql: `${CUBE.id} = ${Products.orderId}`, + products: { + relationship: `many_to_one`, + sql: `${CUBE.id} = ${products.order_id}`, }, }, }); @@ -82,11 +76,11 @@ cube('Orders', { ```yaml cubes: - - name: Orders + - name: orders joins: - - name: Products - relationship: belongs_to - sql: "{CUBE.id} = {Products.order_id}" + - name: products + relationship: many_to_one + sql: '{CUBE.id} = {products.order_id}' ``` @@ -95,40 +89,58 @@ cubes: ### <--{"id" : "Parameters"}--> relationship -`relationship` enables you to describe the join relationship between joined -cubes. It’s important to properly define the type of relationship in order for -Cube to accurately calculate measures. The relationship does not need to be -defined on both cubes, but the definition can affect the [join -direction][ref-schema-fundamentals-join-dir]. +The `relationship` property is used to describe the type of the relationship +between joined cubes. It’s important to properly define the type of relationship +so Cube can accurately calculate measures. + +The cube that declares the join is considered _left_ in terms of the [left +join][wiki-left-join] semantics, and the joined cube is considered _right_. It +means that all rows of the _left_ cube are selected, while only those rows of +the _right_ cube that match the condition are selected as well. For more +information and specific examples, please see [join +directions][ref-schema-fundamentals-join-dir]. -It is very important to define the correct order of cubes in a join. It affects -data in the result-set greatly. The basic cube represents the left entity in a -join, all others would be right. That means that all rows of the left cube are -selected, while rows of the right depend on the condition. For more information -and specific examples, please read about [join directions -here][ref-schema-fundamentals-join-dir]. +The join does not need to be defined on both cubes, but the definition can +affect the [join direction][ref-schema-fundamentals-join-dir]. -The three possible values for a relationship are: +You can use the following types of relationships: + +- `one_to_one` for [one-to-one][wiki-1-1] relationships +- `one_to_many` for [one-to-many][wiki-1-m] relationships +- `many_to_one` for the opposite of [one-to-many][wiki-1-m] relationships + + -#### hasOne +The types of relationships listed above are available since v0.32.19. +Previously, they were known under the following aliases: + +- `one_to_one` as `has_one` and `hasOne` +- `one_to_many` as `has_many` and `hasMany` +- `many_to_one` as `belongs_to` and `belongsTo` + + -A `hasOne` relationship indicates a one-to-one connection with another cube. -This relationship indicates that the one row in the cube can match only one row -in the joined cube. For example, in a model containing users and user profiles, -the users cube would have the following join: +#### One-to-one + +The `one_to_one` type indicates a [one-to-one][wiki-1-1] relationship between +the declaring cube and the joined cube. It means that one row in the declaring +cube can match only one row in the joined cube. + +For example, in a data model containing `users` and their `profiles`, the +`users` cube would declare the following join: ```javascript -cube('Users', { +cube(`users`, { joins: { - Profile: { - relationship: `hasOne`, - sql: `${CUBE}.id = ${Profile.user_id}`, + profiles: { + relationship: `one_to_one`, + sql: `${CUBE}.id = ${profiles.user_id}`, }, }, }); @@ -136,31 +148,32 @@ cube('Users', { ```yaml cubes: - - name: Users + - name: users joins: - - name: Profile - relationship: has_one - sql: "{Users}.id = {Profile.user_id}" + - name: profiles + relationship: one_to_one + sql: '{users}.id = {profiles.user_id}' ``` -#### hasMany +#### One-to-many + +The `one_to_many` type indicates a [one-to-many][wiki-1-m] relationship between +the declaring cube and the joined cube. It means that one row in the declaring +cube can match many rows in the joined cube. -A `hasMany` relationship indicates a one-to-many connection with another cube. -You'll often find this relationship on the "other side" of a `belongsTo` -relationship. This relationship indicates that the one row in the cube can match -many rows in the joined cube. For example, in a model containing authors and -books, the authors cube would have the following join: +For example, in a data model containing `authors` and the `books` they have +written, the `authors` cube would declare the following join: ```javascript -cube('Authors', { +cube(`authors`, { joins: { - Books: { - relationship: `hasMany`, - sql: `${CUBE}.id = ${Books.author_id}`, + books: { + relationship: `one_to_many`, + sql: `${CUBE}.id = ${books.author_id}`, }, }, }); @@ -168,32 +181,34 @@ cube('Authors', { ```yaml cubes: - - name: Authors + - name: authors joins: - - name: Books - relationship: has_many - sql: "{Authors}.id = {Books.author_id}" + - name: books + relationship: one_to_many + sql: '{authors}.id = {books.author_id}' ``` -#### belongsTo +#### Many-to-one -A `belongsTo` relationship indicates a many-to-one connection with another cube. -You’ll often find this relationship on the “other side” of a `hasMany` -relationship. This relationship indicates that the one row of the declaring cube -matches a row in the joined instance, while the joined instance can have many -rows in the declaring cube. For example, in a model containing orders and -customers, the orders cube would have the following join: +The `many_to_one` type indicates the many-to-one relationship between the +declaring cube and the joined cube. You’ll often find this type of relationship +on the opposite side of the [one-to-many][wiki-1-m] relationship. It means that +one row in the declaring cube matches a single row in the joined cube, while a +row in the joined cube can match many rows in the declaring cube. + +For example, in a data model containing `orders` and `customers` who made them, +the `orders` cube would have the following join: ```javascript -cube('Orders', { +cube(`orders`, { joins: { - Customers: { - relationship: `belongsTo`, - sql: `${CUBE}.customer_id = ${Customers.id}`, + customers: { + relationship: `many_to_one`, + sql: `${CUBE}.customer_id = ${customers.id}`, }, }, }); @@ -201,11 +216,11 @@ cube('Orders', { ```yaml cubes: - - name: Orders + - name: orders joins: - - name: Customers - relationship: belongsTo - sql: "{Orders}.customer_id = {Customers.id}" + - name: customers + relationship: many_to_one + sql: '{orders}.customer_id = {customers.id}' ``` @@ -219,13 +234,13 @@ example below: ```javascript -cube('Orders', { +cube(`orders`, { joins: { - Customers: { - relationship: `belongsTo`, - // The `customer_id` field on `Orders` corresponds to the - // `id` field on `Customers` - sql: `${CUBE}.customer_id = ${Customers.id}`, + customers: { + relationship: `many_to_one`, + // The `customer_id` column of the `orders` cube corresponds to the + // `id` dimension of the `customers` cube + sql: `${CUBE}.customer_id = ${customers.id}`, }, }, }); @@ -233,11 +248,11 @@ cube('Orders', { ```yaml cubes: - - name: Orders + - name: orders joins: - - name: Customers - relationship: belongs_to - sql: "{Orders}.customer_id = {Customers.id}" + - name: customers + relationship: many_to_one + sql: '{orders}.customer_id = {customers.id}' ``` @@ -250,7 +265,7 @@ handle row multiplication issues. Let's imagine you want to calculate `Order Amount` by `Order Item Product Name`. In this case, `Order` rows will be multiplied by the `Order Item` join due to -the `hasMany` relationship. In order to produce correct results, Cube will +the `has_many` relationship. In order to produce correct results, Cube will select distinct primary keys from `Order` first and then will join these primary keys with `Order` to get the correct `Order Amount` sum result. Please note that `primaryKey` should be defined in the `dimensions` section. @@ -258,12 +273,12 @@ keys with `Order` to get the correct `Order Amount` sum result. Please note that ```javascript -cube('Orders', { +cube('orders', { dimensions: { - customerId: { + customer_id: { sql: `id`, type: `number`, - primaryKey: true, + primary_key: true, }, }, }); @@ -271,7 +286,7 @@ cube('Orders', { ```yaml cubes: - - name: Orders + - name: orders dimensions: - name: customer_id sql: id @@ -283,7 +298,7 @@ cubes: -Setting `primaryKey` to `true` will change the default value of the `shown` +Setting `primary_key` to `true` will change the default value of the `shown` parameter to `false`. If you still want `shown` to be `true` — set it manually. @@ -291,12 +306,12 @@ parameter to `false`. If you still want `shown` to be `true` — set it manually ```javascript -cube('Orders', { +cube(`orders`, { dimensions: { - customerId: { + customer_id: { sql: `id`, type: `number`, - primaryKey: true, + primary_key: true, shown: true, }, }, @@ -305,7 +320,7 @@ cube('Orders', { ```yaml cubes: - - name: Orders + - name: orders dimensions: - name: customer_id sql: id @@ -329,12 +344,12 @@ depending on your database. ```javascript -cube('Users', { +cube(`users`, { dimensions: { id: { sql: `${CUBE}.user_id || '-' || ${CUBE}.signup_week || '-' || ${CUBE}.activity_week`, type: `string`, - primaryKey: true, + primary_key: true, }, }, }); @@ -342,7 +357,7 @@ cube('Users', { ```yaml cubes: - - name: Users + - name: users dimensions: - name: id sql: "{CUBE}.user_id || '-' || {CUBE}.signup_week || '-' || {CUBE}.activity_week" @@ -363,7 +378,7 @@ as an alias for a basic cube. Take a look at the following example: ```javascript -cube('Users', { +cube(`users`, { dimensions: { name: { sql: `${CUBE}.name`, @@ -375,10 +390,10 @@ cube('Users', { ```yaml cubes: - - name: Users + - name: users dimensions: - name: name - sql: "{CUBE}.name" + sql: '{CUBE}.name' type: string ``` @@ -388,22 +403,22 @@ cubes: -Join graph is directed and `A-B` join is different from `B-A`. [Learn more about -it here][ref-schema-fundamentals-join-dir]. +Join graph is directed and `a → b` join is different from `b → a`. [Learn more +about it here][ref-schema-fundamentals-join-dir]. -Cube automatically takes care of transitive joins. For example if you have the -following schema: +Cube automatically takes care of transitive joins. For example, consider the +following data model: ```javascript -cube(`A`, { +cube(`a`, { joins: { - B: { - sql: `${A}.b_id = ${B}.id`, - relationship: `belongsTo`, + b: { + sql: `${a}.b_id = ${b.id}`, + relationship: `many_to_one`, }, }, @@ -414,11 +429,11 @@ cube(`A`, { }, }); -cube(`B`, { +cube(`b`, { joins: { - C: { - sql: `${B}.c_id = ${C}.id`, - relationship: `belongsTo`, + c: { + sql: `${b}.c_id = ${c.id}`, + relationship: `many_to_one`, }, }, }); @@ -435,20 +450,22 @@ cube(`C`, { ```yaml cubes: - - name: A + - name: a joins: - - name: B - sql: "{A}.b_id = {B}.id" - relationship: belongs_to + - name: b + sql: '{a}.b_id = {b.id}' + relationship: many_to_one measures: - name: count type: count - - name: B + + - name: c joins: - - name: C - sql: "{B}.c_id = {C}.id" - relationship: belongs_to - - name: C + - name: c + sql: '{b}.c_id = {c.id}' + relationship: many_to_one + + - name: c dimensions: - name: category sql: category @@ -457,18 +474,18 @@ cubes: -and the following query: +Assume that the following query is run: ```json { - "measures": ["A.count"], - "dimensions": ["C.category"] + "measures": ["a.count"], + "dimensions": ["c.category"] } ``` -Joins `A-B` and `B-C` will be resolved automatically. Cube uses [Dijkstra -algorithm][wiki-djikstra-alg] to find join path between cubes given requested -members. +Joins `a → b` and `b → c` will be resolved automatically. Cube uses the +[Dijkstra algorithm][wiki-djikstra-alg] to find a join path between cubes given +requested members. [ref-restapi-query-filter-op-set]: /query-format#set [ref-schema-cube-naming]: /schema/reference/cube#naming @@ -477,3 +494,6 @@ members. [ref-schema-cube-sql]: /schema/reference/cube#parameters-sql [ref-schema-data-blenging]: /schema/advanced/data-blending#data-blending [wiki-djikstra-alg]: https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm +[wiki-left-join]: https://en.wikipedia.org/wiki/Join_(SQL)#Left_outer_join +[wiki-1-1]: https://en.wikipedia.org/wiki/One-to-one_(data_model) +[wiki-1-m]: https://en.wikipedia.org/wiki/One-to-many_(data_model) From 13c182f7dcea7cb40d13f69eee2ccb7fcd568082 Mon Sep 17 00:00:00 2001 From: Igor Lukanin Date: Fri, 21 Apr 2023 20:32:56 +0200 Subject: [PATCH 2/8] Update legacy usages of many_to_one --- .../Caching/Getting-Started-Pre-Aggregations.mdx | 2 +- docs/content/Caching/Using-Pre-Aggregations.mdx | 2 +- .../Recipes/column-based-access.mdx | 2 +- .../Recipes/event-analytics.mdx | 11 ++++++----- .../Examples-Tutorials-Recipes/Recipes/funnels.mdx | 4 ++-- .../Advanced/Code-Reusability-Extending-Cubes.mdx | 2 +- docs/content/Schema/Advanced/Polymorphic-Cubes.mdx | 4 ++-- .../Schema/Fundamentals/Additional-Concepts.mdx | 4 ++-- docs/content/Schema/Fundamentals/Concepts.mdx | 6 +++--- .../Schema/Fundamentals/Working-with-Joins.mdx | 14 +++++++------- docs/content/Schema/Reference/cube.mdx | 2 +- docs/content/Schema/Reference/pre-aggregations.mdx | 2 +- 12 files changed, 28 insertions(+), 27 deletions(-) diff --git a/docs/content/Caching/Getting-Started-Pre-Aggregations.mdx b/docs/content/Caching/Getting-Started-Pre-Aggregations.mdx index 9157c3ab83467..fc5149563d485 100644 --- a/docs/content/Caching/Getting-Started-Pre-Aggregations.mdx +++ b/docs/content/Caching/Getting-Started-Pre-Aggregations.mdx @@ -197,7 +197,7 @@ cube(`LineItems`, { joins: { Orders: { sql: `${CUBE}.order_id = ${Orders.id}`, - relationship: `belongsTo`, + relationship: `many_to_one`, }, }, diff --git a/docs/content/Caching/Using-Pre-Aggregations.mdx b/docs/content/Caching/Using-Pre-Aggregations.mdx index a5343317db43f..f3b13d61db3e8 100644 --- a/docs/content/Caching/Using-Pre-Aggregations.mdx +++ b/docs/content/Caching/Using-Pre-Aggregations.mdx @@ -582,7 +582,7 @@ cube(`Orders`, { joins: { Users: { sql: `${CUBE.user_id} = ${Users.id}`, - relationship: `belongsTo` + relationship: `many_to_one` }, }, }); diff --git a/docs/content/Examples-Tutorials-Recipes/Recipes/column-based-access.mdx b/docs/content/Examples-Tutorials-Recipes/Recipes/column-based-access.mdx index 6fb1542d03e84..a438f22e669e7 100644 --- a/docs/content/Examples-Tutorials-Recipes/Recipes/column-based-access.mdx +++ b/docs/content/Examples-Tutorials-Recipes/Recipes/column-based-access.mdx @@ -28,7 +28,7 @@ cube(`Products`, { joins: { Suppliers: { - relationship: `belongsTo`, + relationship: `many_to_one`, sql: `${CUBE}.supplier_id = ${Suppliers.id}`, }, }, diff --git a/docs/content/Examples-Tutorials-Recipes/Recipes/event-analytics.mdx b/docs/content/Examples-Tutorials-Recipes/Recipes/event-analytics.mdx index 57e0172a27f8b..7e06ef77b93a7 100644 --- a/docs/content/Examples-Tutorials-Recipes/Recipes/event-analytics.mdx +++ b/docs/content/Examples-Tutorials-Recipes/Recipes/event-analytics.mdx @@ -254,9 +254,10 @@ The next step is to identify the events contained within the session and the events ending the session. It’s required to get metrics such as session duration and events per session, or to identify sessions where specific events occurred (we’re going to use that for funnel analysis later on). We’re going to -[declare join](/schema/reference/joins), that Events `belongsTo` Sessions and a -specify condition, such as all users' events from session start (inclusive) till -the start of the next session (exclusive) belong to that session. +[declare a join](/schema/reference/joins), that Events have a `many_to_one` +relation to Sessions, and specify a condition, such as all users' events from +session start (inclusive) till the start of the next session (exclusive) belong +to that session. ```javascript cube('Events', { @@ -265,7 +266,7 @@ cube('Events', { // Add the joins block to the Events cube joins: { Sessions: { - relationship: `belongsTo`, + relationship: `many_to_one`, sql: ` ${Events.anonymousId} = ${Sessions.anonymousId} AND ${Events.timestamp} >= ${Sessions.startAt} @@ -382,7 +383,7 @@ cube('Sessions', { // Declare this joins block in the Sessions cube joins: { Identifies: { - relationship: `belongsTo`, + relationship: `many_to_one`, sql: `${Identifies.anonymousId} = ${Sessions.anonymousId}` } }, diff --git a/docs/content/Examples-Tutorials-Recipes/Recipes/funnels.mdx b/docs/content/Examples-Tutorials-Recipes/Recipes/funnels.mdx index 327b3526d15f9..79a2a0e535628 100644 --- a/docs/content/Examples-Tutorials-Recipes/Recipes/funnels.mdx +++ b/docs/content/Examples-Tutorials-Recipes/Recipes/funnels.mdx @@ -264,7 +264,7 @@ steps: [ In order to provide additional dimensions, funnels can be joined with other cubes using `user_id` at the first step of a funnel. This will always use a -`belongsTo` relationship, so hence you should always join with the corresponding +`many_to_one` relationship, so hence you should always join with the corresponding user cube. Here, by 'user' we understand this to be any entity that can go through a sequence of steps within funnel. It could be a real web user with an auto assigned ID or a specific email sent by an email automation that goes @@ -276,7 +276,7 @@ following: cube(`PurchaseFunnel`, { joins: { Users: { - relationship: `belongsTo`, + relationship: `many_to_one`, sql: `${CUBE}.first_step_user_id = ${Users.id}`, }, }, diff --git a/docs/content/Schema/Advanced/Code-Reusability-Extending-Cubes.mdx b/docs/content/Schema/Advanced/Code-Reusability-Extending-Cubes.mdx index 4aab28169dfae..49b94d158df15 100644 --- a/docs/content/Schema/Advanced/Code-Reusability-Extending-Cubes.mdx +++ b/docs/content/Schema/Advanced/Code-Reusability-Extending-Cubes.mdx @@ -41,7 +41,7 @@ cube(`BaseEvents`, { joins: { Users: { - relationship: `belongsTo`, + relationship: `many_to_one`, sql: `${CUBE}.user_id = ${Users.id}`, }, }, diff --git a/docs/content/Schema/Advanced/Polymorphic-Cubes.mdx b/docs/content/Schema/Advanced/Polymorphic-Cubes.mdx index 2b35a460d3d24..51d40f75623f0 100644 --- a/docs/content/Schema/Advanced/Polymorphic-Cubes.mdx +++ b/docs/content/Schema/Advanced/Polymorphic-Cubes.mdx @@ -89,11 +89,11 @@ cube(`Lessons`, { joins: { Students: { - relationship: `belongsTo`, + relationship: `many_to_one`, sql: `${CUBE}.student_id = ${Students.id}`, }, Teachers: { - relationship: `belongsTo`, + relationship: `many_to_one`, sql: `${CUBE}.teacher_id = ${Teachers.id}`, }, }, diff --git a/docs/content/Schema/Fundamentals/Additional-Concepts.mdx b/docs/content/Schema/Fundamentals/Additional-Concepts.mdx index ade69483cf2a8..53d3ba6575b4b 100644 --- a/docs/content/Schema/Fundamentals/Additional-Concepts.mdx +++ b/docs/content/Schema/Fundamentals/Additional-Concepts.mdx @@ -34,12 +34,12 @@ cube(`Orders`, { joins: { Users: { - relationship: `belongsTo`, + relationship: `many_to_one`, sql: `${CUBE}.user_id = ${Users.id}`, }, Products: { - relationship: `belongsTo`, + relationship: `many_to_one`, sql: `${CUBE}.product_id = ${Products.id}`, }, }, diff --git a/docs/content/Schema/Fundamentals/Concepts.mdx b/docs/content/Schema/Fundamentals/Concepts.mdx index 8286b42bb4e35..3ac2760bb9516 100644 --- a/docs/content/Schema/Fundamentals/Concepts.mdx +++ b/docs/content/Schema/Fundamentals/Concepts.mdx @@ -331,7 +331,7 @@ cube('Orders', { joins: { LineItems: { - relationship: `belongsTo`, + relationship: `many_to_one`, // Here we use the `CUBE` global to refer to the current cube, // so the following is equivalent to `Orders.id = LineItems.order_id` sql: `${CUBE}.id = ${LineItems.order_id}`, @@ -348,14 +348,14 @@ cubes: # Here we use the `CUBE` global to refer to the current cube, # so the following is equivalent to `Orders.id = LineItems.order_id` sql: "{CUBE}.id = {LineItems.order_id}" - relationship: belongs_to + relationship: many_to_one ``` There are three kinds of join relationships: -- `belongsTo`/`belongs_to` +- `many_to_one` - `hasOne`/`has_one` - `hasMany`/`has_many` diff --git a/docs/content/Schema/Fundamentals/Working-with-Joins.mdx b/docs/content/Schema/Fundamentals/Working-with-Joins.mdx index 0daee2a7dec99..51c10a4d93a50 100644 --- a/docs/content/Schema/Fundamentals/Working-with-Joins.mdx +++ b/docs/content/Schema/Fundamentals/Working-with-Joins.mdx @@ -14,7 +14,7 @@ supports three kinds of relationships often found in SQL databases: - `hasOne`/`has_one` - `hasMany`/`has_many` -- `belongsTo`/`belongs_to` +- `many_to_one` To use an example, let's use two cubes, `Customers` and `Orders`: @@ -140,7 +140,7 @@ However, if we have guest checkouts, that would mean we would have orders with no matching customer. Looking back at the `hasMany` relationship and its' resulting SQL, any guest checkouts would be excluded from the results. To remedy this, we'll remove the join from the `Customers` cube and instead define a join -with a `belongsTo` relationship on the `Orders` cube: +with a `many_to_one` relationship on the `Orders` cube: @@ -148,7 +148,7 @@ with a `belongsTo` relationship on the `Orders` cube: cube('Orders', { joins: { Customers: { - relationship: `belongsTo`, + relationship: `many_to_one`, sql: `${CUBE}.customer_id = ${Customers.id}`, }, }, @@ -160,7 +160,7 @@ cubes: - name: Orders joins: - name: Customers - relationship: belongs_to + relationship: many_to_one sql: "{CUBE}.customer_id = {Customers.id}" ``` @@ -254,7 +254,7 @@ cube(`Posts`, { joins: { PostTopics: { - relationship: `belongsTo`, + relationship: `many_to_one`, sql: `${CUBE}.id = ${PostTopics.post_id}`, }, }, @@ -505,7 +505,7 @@ cube(`Emails`, { joins: { Campaigns: { - relationship: `belongsTo`, + relationship: `many_to_one`, sql: `${CUBE}.campaign_id = ${Campaigns.id} AND ${CUBE}.customer_name = ${Campaigns.customerName}`, }, @@ -697,7 +697,7 @@ cube('Orders', { joins: { Customers: { - relationship: `belongsTo`, + relationship: `many_to_one`, sql: `${CUBE}.customer_id = ${Customers.id}`, }, }, diff --git a/docs/content/Schema/Reference/cube.mdx b/docs/content/Schema/Reference/cube.mdx index 56b198bf4270a..c9a814948112d 100644 --- a/docs/content/Schema/Reference/cube.mdx +++ b/docs/content/Schema/Reference/cube.mdx @@ -23,7 +23,7 @@ cube(`Users`, { joins: { Organizations: { - relationship: `belongsTo`, + relationship: `many_to_one`, sql: `${Users.organization_id} = ${Organizations.id}`, }, }, diff --git a/docs/content/Schema/Reference/pre-aggregations.mdx b/docs/content/Schema/Reference/pre-aggregations.mdx index 9489b3334ef09..7fcf32bf4c9df 100644 --- a/docs/content/Schema/Reference/pre-aggregations.mdx +++ b/docs/content/Schema/Reference/pre-aggregations.mdx @@ -294,7 +294,7 @@ cube('Orders', { joins: { Users: { - relationship: `belongsTo`, + relationship: `many_to_one`, // Make sure the join uses dimensions on the cube, rather than // the column names from the underlying SQL sql: `${CUBE.user_id} = ${Users.id}`, From e8f8e5631359b1f9c8a01e50e1b8d5d2d31e8277 Mon Sep 17 00:00:00 2001 From: Igor Lukanin Date: Fri, 21 Apr 2023 20:34:24 +0200 Subject: [PATCH 3/8] Update legacy usages of many_to_one (2) --- docs/content/Schema/Fundamentals/Additional-Concepts.mdx | 4 ++-- docs/content/Schema/Fundamentals/Working-with-Joins.mdx | 6 +++--- docs/content/Schema/Reference/cube.mdx | 2 +- docs/content/Schema/Reference/pre-aggregations.mdx | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/docs/content/Schema/Fundamentals/Additional-Concepts.mdx b/docs/content/Schema/Fundamentals/Additional-Concepts.mdx index 53d3ba6575b4b..7e939b25b6b0f 100644 --- a/docs/content/Schema/Fundamentals/Additional-Concepts.mdx +++ b/docs/content/Schema/Fundamentals/Additional-Concepts.mdx @@ -76,10 +76,10 @@ cubes: joins: - name: Users - relationship: belongs_to + relationship: many_to_one sql: "{CUBE}.user_id = {Users}.id" - name: Products - relationship: belongs_to + relationship: many_to_one sql: "{CUBE}.product_id = {Products}.id" measures: diff --git a/docs/content/Schema/Fundamentals/Working-with-Joins.mdx b/docs/content/Schema/Fundamentals/Working-with-Joins.mdx index 51c10a4d93a50..79cbe3ac15205 100644 --- a/docs/content/Schema/Fundamentals/Working-with-Joins.mdx +++ b/docs/content/Schema/Fundamentals/Working-with-Joins.mdx @@ -297,7 +297,7 @@ cubes: sql: SELECT * FROM posts joins: - name: PostTopics - relationship: belongs_to + relationship: many_to_one sql: "{CUBE}.id = {PostTopics.post_id}" - name: Topics @@ -566,7 +566,7 @@ cubes: sql: SELECT * FROM emails joins: - name: Campaigns - relationship: belongs_to + relationship: many_to_one sql: "{CUBE}.campaign_id = {Campaigns.id} AND {CUBE}.customer_name = {Campaigns.customer_name}" measures: - name: count @@ -736,7 +736,7 @@ cubes: sql: SELECT * FROM orders joins: - name: Customers - relationship: belongs_to + relationship: many_to_one sql: "{CUBE}.customer_id = {Customers.id}" measures: - name: count diff --git a/docs/content/Schema/Reference/cube.mdx b/docs/content/Schema/Reference/cube.mdx index c9a814948112d..228539588ece0 100644 --- a/docs/content/Schema/Reference/cube.mdx +++ b/docs/content/Schema/Reference/cube.mdx @@ -61,7 +61,7 @@ cubes: sql: SELECT * FROM USERS joins: - name: Organizations - relationship: belongs_to + relationship: many_to_one sql: "{CUBE.organization_id} = {Organizations.id}" measures: - name: count diff --git a/docs/content/Schema/Reference/pre-aggregations.mdx b/docs/content/Schema/Reference/pre-aggregations.mdx index 7fcf32bf4c9df..30c6360f82625 100644 --- a/docs/content/Schema/Reference/pre-aggregations.mdx +++ b/docs/content/Schema/Reference/pre-aggregations.mdx @@ -367,7 +367,7 @@ cubes: rollups: [Users.users_rollup, CUBE.orders_rollup] joins: - name: Users - relationship: belongs_to + relationship: many_to_one sql: "{CUBE.user_id} = {Users.id}" measures: - name: count From a0be654016ef6907a9625f6bf4c1a92533a5d6fd Mon Sep 17 00:00:00 2001 From: Igor Lukanin Date: Fri, 21 Apr 2023 20:40:37 +0200 Subject: [PATCH 4/8] Update legacy usages of one_to_many --- .../Getting-Started-Pre-Aggregations.mdx | 8 ++-- .../Recipes/entity-attribute-value.mdx | 2 +- .../Fundamentals/Additional-Concepts.mdx | 4 +- docs/content/Schema/Fundamentals/Concepts.mdx | 2 +- .../Fundamentals/Working-with-Joins.mdx | 42 +++++++++---------- docs/content/Schema/Reference/joins.mdx | 2 +- 6 files changed, 30 insertions(+), 30 deletions(-) diff --git a/docs/content/Caching/Getting-Started-Pre-Aggregations.mdx b/docs/content/Caching/Getting-Started-Pre-Aggregations.mdx index fc5149563d485..8490a824c8722 100644 --- a/docs/content/Caching/Getting-Started-Pre-Aggregations.mdx +++ b/docs/content/Caching/Getting-Started-Pre-Aggregations.mdx @@ -167,8 +167,8 @@ receives via the API. The process for selection is summarized below: - The pre-aggregation contains all dimensions, filter dimensions and leaf measures from the query - - The measures aren't multiplied ([via a `hasMany` - relation][ref-schema-joins-hasmany]) + - The measures aren't multiplied ([via a `one_to_many` + relationship][ref-schema-joins-rel]) 3. If no, then check if @@ -425,7 +425,7 @@ To recap what we've learnt so far: - **Additive measures** are measures whose values can be added together -- **Multiplied measures** are measures that define `hasMany` relations +- **Multiplied measures** are measures that define `one_to_many` relationships - **Leaf measures** are measures that do not reference any other measures in their definition @@ -488,7 +488,7 @@ Some extra considerations for pre-aggregation selection: /caching/using-pre-aggregations#pre-aggregations-storage [ref-schema-dims]: /schema/reference/dimensions [ref-schema-joins]: /schema/reference/joins -[ref-schema-joins-hasmany]: /schema/reference/joins#relationship +[ref-schema-joins-rel]: /schema/reference/joins#relationship [ref-schema-preaggs]: /schema/reference/pre-aggregations [ref-schema-preaggs-origsql]: /schema/reference/pre-aggregations#type-originalsql diff --git a/docs/content/Examples-Tutorials-Recipes/Recipes/entity-attribute-value.mdx b/docs/content/Examples-Tutorials-Recipes/Recipes/entity-attribute-value.mdx index d6083b9372c2a..8ec7f50b4b38b 100644 --- a/docs/content/Examples-Tutorials-Recipes/Recipes/entity-attribute-value.mdx +++ b/docs/content/Examples-Tutorials-Recipes/Recipes/entity-attribute-value.mdx @@ -26,7 +26,7 @@ cube(`Users`, { joins: { Orders: { - relationship: 'hasMany', + relationship: 'one_to_many', sql: `${CUBE}.id = ${Orders.userId}`, }, }, diff --git a/docs/content/Schema/Fundamentals/Additional-Concepts.mdx b/docs/content/Schema/Fundamentals/Additional-Concepts.mdx index 7e939b25b6b0f..0679150419372 100644 --- a/docs/content/Schema/Fundamentals/Additional-Concepts.mdx +++ b/docs/content/Schema/Fundamentals/Additional-Concepts.mdx @@ -175,7 +175,7 @@ cube(`SalesManagers`, { joins: { Deals: { - relationship: `hasMany`, + relationship: `one_to_many`, sql: `${CUBE}.id = ${Deals.salesManagerId}`, }, }, @@ -218,7 +218,7 @@ cubes: joins: - name: Deals - relationship: has_many + relationship: one_to_many sql: "{SalesManagers}.id = {Deals}.sales_manager_id" measures: diff --git a/docs/content/Schema/Fundamentals/Concepts.mdx b/docs/content/Schema/Fundamentals/Concepts.mdx index 3ac2760bb9516..8ab2c06ddaa91 100644 --- a/docs/content/Schema/Fundamentals/Concepts.mdx +++ b/docs/content/Schema/Fundamentals/Concepts.mdx @@ -357,7 +357,7 @@ There are three kinds of join relationships: - `many_to_one` - `hasOne`/`has_one` -- `hasMany`/`has_many` +- `one_to_many` More information can be found in the [Joins reference documentation][ref-schema-ref-joins-types]. diff --git a/docs/content/Schema/Fundamentals/Working-with-Joins.mdx b/docs/content/Schema/Fundamentals/Working-with-Joins.mdx index 79cbe3ac15205..8d90348055f28 100644 --- a/docs/content/Schema/Fundamentals/Working-with-Joins.mdx +++ b/docs/content/Schema/Fundamentals/Working-with-Joins.mdx @@ -13,7 +13,7 @@ A join creates a relationship between two cubes in your Cube project. Cube supports three kinds of relationships often found in SQL databases: - `hasOne`/`has_one` -- `hasMany`/`has_many` +- `one_to_many` - `many_to_one` To use an example, let's use two cubes, `Customers` and `Orders`: @@ -83,7 +83,7 @@ We could add a join to the `Customers` cube: cube('Customers', { joins: { Orders: { - relationship: `hasMany`, + relationship: `one_to_many`, sql: `${CUBE}.id = ${Orders.customer_id}`, }, }, @@ -95,7 +95,7 @@ cubes: - name: Customers joins: - name: Orders - relationship: has_many + relationship: one_to_many sql: "{CUBE}.id = {Orders.customer_id}" ``` @@ -137,7 +137,7 @@ LIMIT ``` However, if we have guest checkouts, that would mean we would have orders with -no matching customer. Looking back at the `hasMany` relationship and its' +no matching customer. Looking back at the `one_to_many` relationship and its' resulting SQL, any guest checkouts would be excluded from the results. To remedy this, we'll remove the join from the `Customers` cube and instead define a join with a `many_to_one` relationship on the `Orders` cube: @@ -194,7 +194,7 @@ retrieved. In Cube, joins only need to be defined from one direction. In the above example, -we explicitly _removed_ the `hasMany` relationship from the `Customer` cube; not +we explicitly _removed_ the `one_to_many` relationship from the `Customer` cube; not doing so would cause the query to fail as Cube would be unable to determine a valid join path. [Click here][self-join-direction] to learn more about how the direction of joins affects query results. @@ -240,7 +240,7 @@ and declare the relationships from it to `Topics` cube and from `Posts` to -The following example uses the `hasMany` relationship on the `PostTopics` cube; +The following example uses the `one_to_many` relationship on the `PostTopics` cube; this causes the direction of joins to be `Posts -> PostTopics -> Topics`. [Read more about direction of joins here][self-join-direction]. @@ -277,7 +277,7 @@ cube(`PostTopics`, { joins: { Topic: { - relationship: `hasMany`, + relationship: `one_to_many`, sql: `${CUBE}.topic_id = ${Topics.id}`, }, }, @@ -312,7 +312,7 @@ cubes: sql: SELECT * FROM post_topics joins: - name: Topic - relationship: has_many + relationship: one_to_many sql: "{CUBE}.topic_id = {Topics.id}" dimensions: - name: post_id @@ -494,7 +494,7 @@ The following diagram shows our data schema with the `Campaigns` cube: The last piece is to finally declare a many-to-many relationship. This should be -done by declaring a [`hasMany` relationship][ref-schema-ref-joins-relationship] +done by declaring a [`one_to_many` relationship][ref-schema-ref-joins-relationship] on the associative cube, `Campaigns` in our case. @@ -539,7 +539,7 @@ cube(`Emails`, { cube(`Campaigns`, { joins: { Transactions: { - relationship: `hasMany`, + relationship: `one_to_many`, sql: `${CUBE}.customer_name = ${Transactions.customerName} AND ${CUBE}.campaign_id = ${Transactions.campaignId}`, }, @@ -586,7 +586,7 @@ cubes: - name: Campaigns joins: - name: Transactions - relationship: has_many + relationship: one_to_many sql: "{CUBE}.customer_name = {Transactions.customer_name} AND {CUBE}.campaign_id = {Transactions.campaign_id}" dimensions: - name: id @@ -786,7 +786,7 @@ cube('Customers', { joins: { Orders: { - relationship: `hasMany`, + relationship: `one_to_many`, sql: `${CUBE}.id = ${Orders.customer_id}`, }, }, @@ -820,7 +820,7 @@ cubes: sql: SELECT * FROM customers joins: - name: Orders - relationship: has_many + relationship: one_to_many sql: "{CUBE}.id = {Orders.customer_id}" measures: - name: count @@ -935,11 +935,11 @@ cube(`OrganizationUsers`, { joins: { Users: { sql: `${CUBE}.user_id = ${Users.id}`, - relationship: `hasMany`, + relationship: `one_to_many`, }, Organizations: { sql: `${CUBE}.organization_id = ${Organizations.id}`, - relationship: `hasMany`, + relationship: `one_to_many`, }, }, @@ -984,10 +984,10 @@ cubes: joins: - name: Users sql: "{CUBE}.user_id = {Users.id}" - relationship: has_many + relationship: one_to_many - name: Organizations sql: "{CUBE}.organization_id = {Organizations.id}" - relationship: has_many + relationship: one_to_many dimensions: - name: id # Joins require a primary key, so we'll create one on-the-fly @@ -1032,7 +1032,7 @@ cube(`Users`, { joins: { OrganizationUsers: { sql: `${OrganizationUsers.user_id} = ${Users.id}`, - relationship: `hasMany`, + relationship: `one_to_many`, }, }, @@ -1045,7 +1045,7 @@ cube(`OrganizationUsers`, { joins: { Organizations: { sql: `${OrganizationUsers.organization_id} = ${Organizations.id}`, - relationship: `hasMany`, + relationship: `one_to_many`, }, }, }); @@ -1057,7 +1057,7 @@ cubes: joins: - name: OrganizationUsers sql: "{OrganizationUsers.user_id} = {Users.id}" - relationship: has_many + relationship: one_to_many measures: - name: type type: count @@ -1066,7 +1066,7 @@ cubes: joins: - name: Organizations sql: "{OrganizationUsers.organization_id} = {Organizations.id}" - relationship: has_many + relationship: one_to_many ``` diff --git a/docs/content/Schema/Reference/joins.mdx b/docs/content/Schema/Reference/joins.mdx index e0cf205c7488a..0e9970338b91d 100644 --- a/docs/content/Schema/Reference/joins.mdx +++ b/docs/content/Schema/Reference/joins.mdx @@ -265,7 +265,7 @@ handle row multiplication issues. Let's imagine you want to calculate `Order Amount` by `Order Item Product Name`. In this case, `Order` rows will be multiplied by the `Order Item` join due to -the `has_many` relationship. In order to produce correct results, Cube will +the `one_to_many` relationship. In order to produce correct results, Cube will select distinct primary keys from `Order` first and then will join these primary keys with `Order` to get the correct `Order Amount` sum result. Please note that `primaryKey` should be defined in the `dimensions` section. From 8b291a0deaa44d1fd6e76dbdfb24a99e47f5b07e Mon Sep 17 00:00:00 2001 From: Igor Lukanin Date: Fri, 21 Apr 2023 20:48:10 +0200 Subject: [PATCH 5/8] Update legacy usages of one_to_one --- .../Recipes/column-based-access.mdx | 2 +- docs/content/Schema/Fundamentals/Concepts.mdx | 10 ++-------- .../content/Schema/Fundamentals/Working-with-Joins.mdx | 5 +++-- docs/content/Schema/Reference/cube.mdx | 4 ++-- 4 files changed, 8 insertions(+), 13 deletions(-) diff --git a/docs/content/Examples-Tutorials-Recipes/Recipes/column-based-access.mdx b/docs/content/Examples-Tutorials-Recipes/Recipes/column-based-access.mdx index a438f22e669e7..f3007302c6ed4 100644 --- a/docs/content/Examples-Tutorials-Recipes/Recipes/column-based-access.mdx +++ b/docs/content/Examples-Tutorials-Recipes/Recipes/column-based-access.mdx @@ -19,7 +19,7 @@ To implement column-based access, we will use supplier's email from a [`queryRewrite`](https://cube.dev/docs/security/context#using-query-rewrite) extension point to manage data access. -We have `Products` and `Suppliers` cubes with a `hasOne` relationship from +We have `Products` and `Suppliers` cubes with a `many_to_one` relationship from products to suppliers: ```javascript diff --git a/docs/content/Schema/Fundamentals/Concepts.mdx b/docs/content/Schema/Fundamentals/Concepts.mdx index 8ab2c06ddaa91..6c36185e89354 100644 --- a/docs/content/Schema/Fundamentals/Concepts.mdx +++ b/docs/content/Schema/Fundamentals/Concepts.mdx @@ -353,14 +353,8 @@ cubes: -There are three kinds of join relationships: - -- `many_to_one` -- `hasOne`/`has_one` -- `one_to_many` - -More information can be found in the [Joins reference -documentation][ref-schema-ref-joins-types]. +There are the three [types of join relationships][ref-schema-ref-joins-types]: +`one_to_one`, `one_to_many`, and `many_to_one`. ## Segments diff --git a/docs/content/Schema/Fundamentals/Working-with-Joins.mdx b/docs/content/Schema/Fundamentals/Working-with-Joins.mdx index 8d90348055f28..0b0978bde34d0 100644 --- a/docs/content/Schema/Fundamentals/Working-with-Joins.mdx +++ b/docs/content/Schema/Fundamentals/Working-with-Joins.mdx @@ -10,9 +10,10 @@ redirect_from: --- A join creates a relationship between two cubes in your Cube project. Cube -supports three kinds of relationships often found in SQL databases: +supports three [types of join relationships][ref-schema-ref-joins-relationship] +often found in SQL databases: -- `hasOne`/`has_one` +- `one_to_one` - `one_to_many` - `many_to_one` diff --git a/docs/content/Schema/Reference/cube.mdx b/docs/content/Schema/Reference/cube.mdx index 228539588ece0..c899466a9b8b1 100644 --- a/docs/content/Schema/Reference/cube.mdx +++ b/docs/content/Schema/Reference/cube.mdx @@ -118,7 +118,7 @@ cube(`Users`, { joins: { Contacts: { sql: `${CUBE}.contact_id = ${Contacts.id}`, - relationship: `hasOne`, + relationship: `one_to_one`, }, }, @@ -156,7 +156,7 @@ cubes: joins: - name: Contacts sql: "{CUBE.contact_id} = {Contacts.id}" - relationship: has_one + relationship: one_to_one dimensions: - name: name sql: "COALESCE({CUBE.name}, {Contacts.name})" From d64b7bc92a9d1e7e4e23ad5555dc3fd854a5abdb Mon Sep 17 00:00:00 2001 From: Igor Lukanin Date: Fri, 21 Apr 2023 21:00:11 +0200 Subject: [PATCH 6/8] Clarify the disclaimer --- docs/content/Schema/Reference/joins.mdx | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/docs/content/Schema/Reference/joins.mdx b/docs/content/Schema/Reference/joins.mdx index 0e9970338b91d..cdcf85250496e 100644 --- a/docs/content/Schema/Reference/joins.mdx +++ b/docs/content/Schema/Reference/joins.mdx @@ -115,12 +115,13 @@ You can use the following types of relationships: -The types of relationships listed above are available since v0.32.19. -Previously, they were known under the following aliases: +The types of relationships listed above were introduced in v0.32.19 for clarity as +they are commonly used in the data space. The following aliases were used before and +are still valid, so there's no need to update existing data models: -- `one_to_one` as `has_one` and `hasOne` -- `one_to_many` as `has_many` and `hasMany` -- `many_to_one` as `belongs_to` and `belongsTo` +- `one_to_one` was known as `has_one` or `hasOne` +- `one_to_many` was known as `has_many` or `hasMany` +- `many_to_one` was known as `belongs_to` or `belongsTo` From e4a52b9a4b37dc29992b97085e9f0a1c483c709c Mon Sep 17 00:00:00 2001 From: Igor Lukanin Date: Sat, 22 Apr 2023 16:29:04 +0200 Subject: [PATCH 7/8] Update docs/content/Examples-Tutorials-Recipes/Recipes/funnels.mdx Co-authored-by: Hassan Khan --- docs/content/Examples-Tutorials-Recipes/Recipes/funnels.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/content/Examples-Tutorials-Recipes/Recipes/funnels.mdx b/docs/content/Examples-Tutorials-Recipes/Recipes/funnels.mdx index 79a2a0e535628..745500e4bc7a9 100644 --- a/docs/content/Examples-Tutorials-Recipes/Recipes/funnels.mdx +++ b/docs/content/Examples-Tutorials-Recipes/Recipes/funnels.mdx @@ -264,7 +264,7 @@ steps: [ In order to provide additional dimensions, funnels can be joined with other cubes using `user_id` at the first step of a funnel. This will always use a -`many_to_one` relationship, so hence you should always join with the corresponding +`many_to_one` relationship, hence you should always join with the corresponding user cube. Here, by 'user' we understand this to be any entity that can go through a sequence of steps within funnel. It could be a real web user with an auto assigned ID or a specific email sent by an email automation that goes From b804a92aabd4662c1f5ff644e49626f19dde6832 Mon Sep 17 00:00:00 2001 From: Igor Lukanin Date: Sat, 22 Apr 2023 16:29:15 +0200 Subject: [PATCH 8/8] Update docs/content/Schema/Fundamentals/Working-with-Joins.mdx Co-authored-by: Hassan Khan --- docs/content/Schema/Fundamentals/Working-with-Joins.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/content/Schema/Fundamentals/Working-with-Joins.mdx b/docs/content/Schema/Fundamentals/Working-with-Joins.mdx index 0b0978bde34d0..1fae1c51588e6 100644 --- a/docs/content/Schema/Fundamentals/Working-with-Joins.mdx +++ b/docs/content/Schema/Fundamentals/Working-with-Joins.mdx @@ -13,7 +13,7 @@ A join creates a relationship between two cubes in your Cube project. Cube supports three [types of join relationships][ref-schema-ref-joins-relationship] often found in SQL databases: -- `one_to_one` +- `one_to_one` - `one_to_many` - `many_to_one`