Skip to content

Model Relations

In this section, we’ll go through how relations work in NimbusDB and how to define and manage them in your models. We’ll use items and shop models for our examples.

// `items` model
items = new NimbusDBModel("global", "items", {
id: {
type: NIMBUSDB_DATA_TYPE.INTEGER,
const: NIMBUSDB_CONSTRAINT.PRIMARY_KEY
},
name: NIMBUSDB_DATA_TYPE.STRING,
price: {
type: NIMBUSDB_DATA_TYPE.NUMBER,
validator: function(data, value) {
return value >= 0;
},
default_value: 0
},
is_locked: {
type: NIMBUSDB_DATA_TYPE.BOOLEAN,
const: NIMBUSDB_CONSTRAINT.OPTIONAL,
default_value: false
}
}, [
{ id: 1, name: "Apple", price: 5 },
{ id: 2, name: "Banana", price: 7.2 },
{ id: 3, name: "Cherry", price: 15 },
{ id: 4, name: "Date", price: 12.5 },
{ id: 5, name: "Elderberry", price: 8 },
{ id: 6, name: "Fig", price: 10 },
{ id: 7, name: "Grape", price: 6 },
{ id: 8, name: "Honeydew", price: 9 },
{ id: 9, name: "Kiwi", price: 4 },
{ id: 10, name: "Lemon", price: 3 }
]);
// `shop_items` model
shop_items = new NimbusDBModel("global", "shop_items", {
id: {
type: NIMBUSDB_DATA_TYPE.INTEGER,
const: NIMBUSDB_CONSTRAINT.PRIMARY_KEY
},
item_id: NIMBUSDB_DATA_TYPE.INTEGER,
stock: NIMBUSDB_DATA_TYPE.INTEGER
}, [
{ id: 1, item_id: 1, stock: 20 },
{ id: 2, item_id: 2, stock: 17 },
{ id: 3, item_id: 3, stock: 23 },
{ id: 4, item_id: 3, stock: 50 },
{ id: 5, item_id: 5, stock: 10 }
]);

NimbusDB provides a simple way to define relations between models, either in models or catalogs.

A “blind” relation that defined one-sided. In other words, the target model has no knowledge of the source model.

// define relation from shop_items.item_id to items.id
var rel_id = shop_items.define_relation(items, "item_id", "id");
// in case you want to to get the relation id later
var shop_items_rel = shop_items.get_relation("items", "item_id", "id");

Based on the example above, we got this:

┏━━━━━━━━━━━━━━┓ ┏━━━━━━━━━━━┓
┃ shop_items ┃ ┃ items ┃
┣━━━━━━━━━━━━━━┫ ┣━━━━━━━━━━━┫
│ id │ ┌─────>│ id │
├──────────────┤ │ ├───────────┤
│ item_id │──────┘ │ name │
├──────────────┤ ├───────────┤
│ stock │ │ price │
└──────────────┘ ├───────────┤
│ is_locked │
└───────────┘

item_id column in shop_items model is the foreign key that points to the id column in items model.

As you can see, it just one-way relation. So, later we can resolve shop_items.item_id to items.id, but we can’t resolve items.id to shop_items.item_id. We’ll cover this in Data Resolving section.

A mutual relation between two models. Both models will have knowledge of each other.

// define relation from shop_items.item_id to items.id
shop_items.define_relation(items, "item_id", "id");
// and then from items.id to shop_items.item_id
items.define_relation(shop_items, "id", "item_id");

Based on the example above, we got this:

┏━━━━━━━━━━━━━━┓ ┏━━━━━━━━━━━┓
┃ shop_items ┃ ┃ items ┃
┣━━━━━━━━━━━━━━┫ ┣━━━━━━━━━━━┫
│ id │ ┌─────>│ id │
├──────────────┤ │ ├───────────┤
│ item_id │<─────┘ │ name │
├──────────────┤ ├───────────┤
│ stock │ │ price │
└──────────────┘ ├───────────┤
│ is_locked │
└───────────┘

We can resolve both shop_items.item_id to items.id and items.id to shop_items.item_id.

For the example above, we got 2 different perspectives:

  1. From shop_items model perspective:

    • shop_items model needs items model’s data through item_id column.
    • With this, we have “The first item in the shop_items will sell which item?”-like question.
  2. From items model perspective:

    • items model has shop_items model’s data through id column.
    • With this, we have “Which shop sells this item?” or “Where do I get this item?” question.

If you’re using catalog, you can define relations cleaner. Let’s use this catalog:

ctg_items = new NimbusDBCatalog("shop_catalog", {
model: [items, shop]
});
// define relation from shop_items.item_id to items.id
ctg_items.define_relation("shop_items", "item_id", "items", "id"); // using model name and column name
ctg_items.define_relation("shop_items.item_id = items.id"); // using model-column string
ctg_items.define_relation([ // using array of model-column strings
"shop_items.item_id = items.id",
"...relN"
]);
ctg_items.define_relation({ // using relation selector, array of this object is also allowed
from: "shop_items", // `from` and `to` can be model name, custom id, or model instance
from_column: "item_id", // `from_column` and `to_column` must be string (the column name)
to: "items",
to_column: "id"
});
// define relation from shop_items.item_id to items.id and vice versa
// when using `.define_relation()`, set `bidirectional: true` option
// works on any style/format that is accepted by `.define_relation()`
ctg_items.define_relation("shop_items", "item_id", "items", "id", {
bidirectional: true
});
// you can also use the bidirectional operators instead
ctg_items.define_relation("shop_items.item_id <=> items.id");
// or use `.define_mutual_relation()` to enable the bidirectional relation by default
ctg_items.define_mutual_relation("shop_items", "item_id", "items", "id");
ctg_items.define_mutual_relation("shop_items.item_id = items.id"); // using model-column string
ctg_items.define_mutual_relation([ // using array of model-column strings
"shop_items.item_id = items.id",
"...relN"
]);
ctg_items.define_mutual_relation({ // using relation selector, array of this object is also allowed
from: "shop_items", // `from` and `to` can be model name, custom id, or model instance
from_column: "item_id", // `from_column` and `to_column` must be string (the column name)
to: "items",
to_column: "id"
});

If you’re using string-selector format for defining relations ("model1.from_col {operator} model2.to_col"), you can use the following operators:

OperatorTypeDescription
=, ->, =>One-wayDefines a relation from left model to right model.
<-, <=One-wayDefines a relation from right model to left model.
<->, <=>BidirectionalDefines a relation from left model to right model and vice versa.
// using one-way operator
// from left (source) to right (target)
ctg_items.define_relation("shop_items.item_id = items.id");
ctg_items.define_relation("shop_items.item_id -> items.id");
ctg_items.define_relation("shop_items.item_id => items.id");
// from right (source) to left (target)
ctg_items.define_relation("shop_items.item_id <- items.id");
ctg_items.define_relation("shop_items.item_id <= items.id");
// using bidirectional operator
ctg_items.define_relation("shop_items.item_id <-> items.id");
ctg_items.define_relation("shop_items.item_id <=> items.id");

Represents a defined relationship between two models, linking a column in the source model to a column in the target model.

relation.d.ts
class NimbusDBRelation {
constructor(
_model: NimbusDBModel,
_name_id: string | int,
_from_column: string,
_to_column: string,
_options?: NimbusDBRelationOptions
)
custom_id: int | undefined;
from_column: string;
id: int;
is_primary: boolean;
model: NimbusDBModel | undefined;
name: string | undefined;
to_column: string;
static __id: int;
}

Defines a one-way relation between models.

model.d.ts
class NimbusDBModel {
// ... other methods and properties ...
static define_relation(
_to_model: NimbusDBModel,
_from_column: string,
_to_column: string,
_option?: NimbusDBRelationOptions
): int | NimbusDBRelation;
}
  • Type: NimbusDBModel
  • The target model of this relation.
  • Type: string
  • The column in the source model used for the join.
  • Type: string
  • The column in the target model used for the join.
  • Type: NimbusDBRelationOptions
  • Default: undefined
  • Optional configuration for the relation.
  • Type: int | NimbusDBRelation
  • The relation id. If return_object option is set to true, returns the NimbusDBRelation instance.

Drops a one-way relation from the model.

model.d.ts
class NimbusDBModel {
// ... other methods and properties ...
static drop_relation(
_relation_id: int
): void;
}
  • Type: int
  • The id of the relation to drop. Can be obtained from .define_relation() or .get_relation().

Retrieves a relation from the model.

model.d.ts
class NimbusDBModel {
// ... other methods and properties ...
static get_relation(
_model_name_id: string | int,
_from_column: string,
_to_column: string,
_options?: NimbusDBGetRelationOptions
): int | NimbusDBRelation | undefined;
}
  • Type: string | int
  • The name or custom ID of the model.
  • Type: string
  • The column in the source model used for the join.
  • Type: string
  • The column in the target model used for the join.
  • Type: NimbusDBGetRelationOptions
  • Default: undefined
  • Optional configuration for the relation.
  • Type: int | NimbusDBRelation | undefined
  • The relation id. Returns NimbusDBRelation instance if return_object option is set to true. Returns undefined if the relation cannot be found.

Defines a directional relation between two models using a selector string or object.

catalog.d.ts
class NimbusDBCatalog {
// ... other methods and properties ...
static define_relation(
_from_model: string,
_from_column: string,
_to_model: string,
_to_column: string,
_options?: NimbusDBCatalogRelationOptions
): int | NimbusDBRelation | undefined;
}
  • Type: string
  • The source model name.
  • Type: string
  • The column in the source model used for the join.
  • Type: string
  • The target model name.
  • Type: string
  • The column in the target model used for the join.
  • Type: NimbusDBCatalogRelationOptions
  • Default: undefined
  • Optional configuration for the relation.
  • Type: int | NimbusDBRelation | undefined
  • The relation id. Returns NimbusDBRelation instance if return_object option is set to true. Returns undefined if the relation cannot be found.

Defines a bidirectional relation between two models using a selector string or object.

catalog.d.ts
class NimbusDBCatalog {
// ... other methods and properties ...
static define_mutual_relation(
_from_model: string,
_from_column: string,
_to_model: string,
_to_column: string,
_options?: NimbusDBCatalogRelationOptions
): int | NimbusDBRelation | undefined;
}
  • Type: string
  • The source model name.
  • Type: string
  • The column in the source model used for the join.
  • Type: string
  • The target model name.
  • Type: string
  • The column in the target model used for the join.
  • Type: NimbusDBCatalogRelationOptions
  • Default: undefined
  • Optional configuration for the relation.
  • Type: int | NimbusDBRelation | undefined
  • The relation id. Returns NimbusDBRelation instance if return_object option is set to true. Returns undefined if the relation cannot be found.

Drops a relation between two models.

catalog.d.ts
class NimbusDBCatalog {
// ... other methods and properties ...
static drop_relation(
_from_model: string | int | NimbusDBModel,
_from_column: string,
_to_model: string | int | NimbusDBModel,
_to_column: string
): void;
}
  • Type: string | int | NimbusDBModel
  • The source model name, custom id, or model instance.
  • Type: string
  • The column in the source model used for the join.
  • Type: string | int | NimbusDBModel
  • The target model name, custom id, or model instance.
  • Type: string
  • The column in the target model used for the join.

Retrieves a relation between two models.

catalog.d.ts
class NimbusDBCatalog {
// ... other methods and properties ...
static get_relation(
_from_model: string | int | NimbusDBModel,
_from_column: string,
_to_model: string | int | NimbusDBModel,
_to_column: string,
_options?: NimbusDBGetRelationOptions
): int | NimbusDBRelation | undefined;
}
  • Type: string | int | NimbusDBModel
  • The source model name, custom id, or model instance.
  • Type: string
  • The column in the source model used for the join.
  • Type: string | int | NimbusDBModel
  • The target model name, custom id, or model instance.
  • Type: string
  • The column in the target model used for the join.
  • Type: NimbusDBGetRelationOptions
  • Default: undefined
  • Optional configuration for the relation.
  • Type: int | NimbusDBRelation | undefined
  • The relation id. Returns NimbusDBRelation instance if return_object option is set to true. Returns undefined if the relation cannot be found.
relation.d.ts
type NimbusDBRelationSelector = {
from: string | int | NimbusDBModel; // int = model's custom_id
from_column: string;
to: string | int | NimbusDBModel; // int = model's custom_id
to_column: string;
options?: NimbusDBGetRelationOptions;
};

Optional configurations for the relation.

relation.d.ts
type NimbusDBRelationOptions = Partial<{
is_primary: boolean; // whether the target model's column is a primary key for that model (default = false)
use_custom_id: boolean; // use custom_id instead of name (default = false)
}>;

Optional configurations for .get_relation() method.

model.d.ts
type NimbusDBGetRelationOptions = Partial<{
return_object: boolean; // return relation object instead of system id (default = false)
temporary: boolean; // force creating new relation and don't store in relations array (default = false)
use_custom_id: boolean; // use custom_id instead of name (default = false)
}>;

Optional configurations for .define_relation() and .define_mutual_relation() methods.

catalog.d.ts
type NimbusDBCatalogRelationOptions = Partial<{
bidirectional: boolean; // make the relation bidirectional (default = false)
}> & NimbusDBGetRelationOptions;