Data Resolve
In this section, we will discuss how to resolve data from a record to another model’s record(s).
We’ll use this diagram for our examples:
┏━━━━━━━━━━┓ ┏━━━━━━━━━━━━┓ ┏━━━━━━━━━━━┓┃ shops ┃ ┃ shop_items ┃ ┃ items ┃┣━━━━━━━━━━┫ ┣━━━━━━━━━━━━┫ ┣━━━━━━━━━━━┫│ id │<─────┐ │ id │ ┌─────>│ id │├──────────┤ │ ├────────────┤ │ ├───────────┤│ name │ └─────>│ shop_id │ │ │ name │├──────────┤ ├────────────┤ │ ├───────────┤│ location │ │ item_id │<─────┘ │ price │└──────────┘ ├────────────┤ ├───────────┤ │ stock │ │ is_locked │ └────────────┘ └───────────┘// `shops` modelshops = new NimbusDBModel("global", "shops", { id: { type: NIMBUSDB_DATA_TYPE.INTEGER, const: NIMBUSDB_CONSTRAINT.PRIMARY_KEY }, name: NIMBUSDB_DATA_TYPE.STRING, location: NIMBUSDB_DATA_TYPE.STRING}, [ { id: 1, name: "Starter Shop", location: "Town 1" }, { id: 2, name: "Adventurer's Guild", location: "Alpha Dungeon" }, { id: 3, name: "Grand Capital Mart", location: "Capital City" }]);
// `shop_items` modelshop_items = new NimbusDBModel("global", "shop_items", { id: { type: NIMBUSDB_DATA_TYPE.INTEGER, const: NIMBUSDB_CONSTRAINT.PRIMARY_KEY }, shop_id: NIMBUSDB_DATA_TYPE.INTEGER, item_id: NIMBUSDB_DATA_TYPE.INTEGER, stock: NIMBUSDB_DATA_TYPE.INTEGER}, [ { id: 1, shop_id: 1, item_id: 1, stock: 20 }, { id: 2, shop_id: 1, item_id: 2, stock: 17 }, { id: 3, shop_id: 1, item_id: 3, stock: 23 }, { id: 4, shop_id: 2, item_id: 3, stock: 50 }, { id: 5, shop_id: 3, item_id: 5, stock: 10 }]);
// `items` modelitems = 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 }]);
// register all models to a catalogctg_items = new NimbusDBCatalog("items", { model: [shops, shop_items, items]});
// define relationsctg_items.define_relation([ "shops.id <=> shop_items.shop_id", "items.id <=> shop_items.item_id"]);Resolving Data
Section titled “Resolving Data”Resolving data means we fetch and add the related record(s) into the current record(s) by using the provided foreign-key column. It’s a clean way to get combined records from current model with other model(s) without need to .join() the related model(s).
By Column
Section titled “By Column”The simplest way to resolve data is to use the .resolve() method with a column name that acts as a foreign-key column.
// (1) column intersectionvar shop_item1_res = shop_items.find(1).resolve("item_id", items);// this will resolve `shop_items.item_id` -> `items.item_id`, which is not what we want (there's no `items.item_id`)// this form is useful if the both models use the same column name as foreign-primary key// so, shop_item1_res will be `undefined`
// (2) different column names// `on` option specify which column in `with` model that should be used as primary-key columnvar shop_item1_res = shop_items.find(1).resolve("item_id", items, { on: "id"});// so, this will resolve `shop_items.item_id` -> `items.id`// which means this will resolve `shop_item` with `id = 1` to `items` with `id = 1`// so, shop_item1_res has value: {// id: 1,// shop_id: 1,// item_id: { id: 1, name: "Apple", price: 5 },// stock: 20// }
// (3) resolve to different column name// `as` option to specify the column name used for storing resolved datavar shop_item1_res = shop_items.find(1).resolve("item_id", items, { on: "id", as: "item"});// so, this will resolve `shop_items.item_id` -> `items.id`// which means this will resolve `shop_item` with `id = 1` to `items` with `id = 1`// so, shop_item1_res has value: {// id: 1,// shop_id: 1,// item_id: 1, // <- the original value// stock: 20,// item: { id: 1, name: "Apple", price: 5 }// }
// (4) if the resolved records is more than 1var shops1 = shops.find(1).resolve("id", shop_items, { on: "shop_id", as: "shop_items", match_all: true // if not set, it will only resolve the first record});// so, this will resolve `shops.id` -> `shop_items.shop_id`// which means this will resolve `shop` with `id = 1` to `shop_items` with `shop_id = 1`// so, shops1 has value: {// id: 1,// name: "Starter Shop",// location: "Town 1",// shop_items: [// { id: 1, shop_id: 1, item_id: 1, stock: 20 },// { id: 2, shop_id: 1, item_id: 2, stock: 17 },// { id: 3, shop_id: 1, item_id: 3, stock: 23 }// ]// }
// (5) resolve multiple timesvar shop_item2_res = shop_items.find(2) .resolve("item_id", items, { // first, resolve `shop_items.item_id` -> `items.id` on: "id", as: "item" }) .resolve("shop_id", shops, { // then, resolve `shop_items.shop_id` -> `shops.id` on: "id", as: "shop" }) .print(); // (for debugging purpose) show final resolved record// so, this will resolve `shop_items.item_id` -> `items.id` and `shop_items.shop_id` -> `shops.id`// which means this will resolve `shop_item` with `id = 2` to `items` with `id = 2` and `shops` with `id = 1`// so, shop_item2_res has value: {// id: 2,// shop_id: 1,// item_id: 2,// stock: 17,// item: { id: 2, name: "Banana", price: 7.2 },// shop: { id: 1, name: "Starter Shop", location: "Town 1" }// }By Relation
Section titled “By Relation”If you already defined relation(s) between current model and other model(s), you can use the relation id or relation object to resolve the related data.
// (1) using relation idvar rel_id = shop_items.get_relation("items", "item_id", "id");var shop_item1_res = shop_items.find(1).resolve(rel_id);// in this case, the `on` option is not needed since it's already defined in the relation// so, this will resolve `shop_items.item_id` -> `items.id`// which means this will resolve `shop_item` with `id = 1` to `items` with `id = 1`// so, shop_item1_res has value: {// id: 1,// shop_id: 1,// item_id: { id: 1, name: "Apple", price: 5 },// stock: 20// }
// (2) using relation objectvar rel = shop_items.get_relation("items", "item_id", "id", { return_object: true });var shop_item1_res = shop_items.find(1).resolve(rel);// same as (1)
// (3) using relation object with optionsvar rel_id = shop_items.get_relation("items", "item_id", "id");var shop_item1_res = shop_items.find(1).resolve(rel_id, { as: "item"});// shop_item1_res has value: {// id: 1,// shop_id: 1,// item_id: 1,// stock: 20,// item: { id: 1, name: "Apple", price: 5 }// }By Resolver Map
Section titled “By Resolver Map”This form is great for when you have multiple columns to resolve at once.
// (1) column intersectionvar shop_item1_res = shop_items.find(1).resolve({ item_id: { with_model: items }});// resolve `shop_items.item_id` -> `items.item_id`// shop_item1_res has `undefined` value, because there's no `item_id` column in `items` model
// (2) column mappingvar shop_item1_res = shop_items.find(1).resolve({ item_id: { with_model: items, on: "id" }});// resolve `shop_items.item_id` -> `items.id`// shop_item1_res has value: {// id: 1,// shop_id: 1,// item_id: { id: 1, name: "Apple", price: 5 },// stock: 20// }
// (3) resolve with different column namevar shop_item1_res = shop_items.find(1).resolve({ item_id: { with_model: items, on: "id", as: "item" }});// resolve `shop_items.item_id` -> `items.id`// shop_item1_res has value: {// id: 1,// shop_id: 1,// item_id: 1,// stock: 20,// item: { id: 1, name: "Apple", price: 5 }// }
// (4) resolve multiple columnsvar shop_item1_res = shop_items.find(1).resolve({ item_id: { with_model: items, on: "id", as: "item" }, shop_id: { with_model: shops, on: "id", as: "shop" }});// resolve `shop_items.item_id` -> `items.id` and `shop_items.shop_id` -> `shops.id`// shop_item1_res has value: {// id: 1,// shop_id: 1,// item_id: 1,// stock: 20,// item: { id: 1, name: "Apple", price: 5 },// shop: { id: 1, name: "Starter Shop", location: "Town 1" }// }Resolving Multiple Foreign Keys
Section titled “Resolving Multiple Foreign Keys”Let’s add another record to the shop_items model for demonstration.
shop_items.insert({ id: 6, shop_id: 3, item_id: [1, 2, 4, 6], // multiple foreign keys stock: 3, __force: true // force insert, only for example});
var shop_item6_res = shop_items.find(6).resolve("item_id", items, { on: "id", as: "items"});// resolve `shop_items.item_id` -> `items.id`// shop_item6_res has value: {// id : 6,// shop_id : 3,// items : [// { id : 1, price : 5, name : "Apple", is_locked : 0, color : "red" },// { id : 2, price : 7.20, name : "Banana", is_locked : 0, color : "yellow" },// { id : 4, price : 12.50, name : "Date", is_locked : 0, color : "green" },// { id : 6, price : 10, name : "Fig", is_locked : 0, color : "purple" }// ],// item_id : [ 1,2,4,6 ],// stock : 2// }Expanding Resolved Data
Section titled “Expanding Resolved Data”By default, .resolve() will resolve the related data to the column name that acts as the foreign key (or column specified by as option). If you need to merge it with the source record, you can use the expand or populate option.
var shop_item1_res = shop_items.find(1).resolve("item_id", items, { on: "id", expand: true // or `populate: true`});// resolve `shop_items.item_id` -> `items.id`// shop_item1_res has value: {// id: 1,// shop_id: 1,// item_id: 1,// stock: 20,// name: "Apple", // from `items.name` column// price: 5 // from `items.price` column// }References
Section titled “References”Data.resolve()
Section titled “Data.resolve()”Resolves a foreign-key column by looking up the related record in another model.
Signature
Section titled “Signature”class NimbusDBData { // ... other methods and properties ... static resolve( _column: string, _with: NimbusDBModel, _options?: Partial<NimbusDBDataResolve> ): NimbusDBData;}Parameters
Section titled “Parameters”_column
Section titled “_column”- Type:
string - The column name in both
thisdata and_withmodel.
- Type:
NimbusDBModel - The model to resolve against.
_options
Section titled “_options”- Type:
Partial<NimbusDBDataResolve> - Default:
undefined - Optional options for resolving the data.
Returns
Section titled “Returns”- Type:
NimbusDBData - The modified
NimbusDBDatainstance after resolution.
Signature
Section titled “Signature”class NimbusDBData { // ... other methods and properties ... static resolve( _rel: int | NimbusDBRelation, _options?: Partial<NimbusDBDataResolve> ): NimbusDBData;}Parameters
Section titled “Parameters”- Type:
int|NimbusDBRelation - The relation id or relation object to resolve against.
_options
Section titled “_options”- Type:
Partial<NimbusDBDataResolve> - Default:
undefined - Optional options for resolving the data.
Returns
Section titled “Returns”- Type:
NimbusDBData - The modified
NimbusDBDatainstance after resolution.
Signature
Section titled “Signature”class NimbusDBData { // ... other methods and properties ... static resolve( _resolver: { [column_name: string]: NimbusDBDataResolve; }, _options?: NimbusDBDataResolveOptions ): NimbusDBData;}Parameters
Section titled “Parameters”_resolver
Section titled “_resolver”- Type:
{ [column_name: string]: NimbusDBDataResolve; } - The resolver object that defines how to resolve the data. The key is column name of this record to be resolved, and the value is
NimbusDBDataResolveobject.
_options
Section titled “_options”- Type:
Partial<NimbusDBDataResolveOptions> - Default:
undefined - Optional options for resolving the data.
Returns
Section titled “Returns”- Type:
NimbusDBData - The modified
NimbusDBDatainstance after resolution.
NimbusDBDataResolve
Section titled “NimbusDBDataResolve”Object for resolving data by object form.
type NimbusDBDataResolve = { with_model: NimbusDBModel;
as?: string; // set new property instead of overwriting the original (default = undefined). no effect if `expand` is true expand?: boolean; // set the result directly to the data isolate?: boolean; // return an isolated copy of the data after the operation (default = false) match_all?: boolean; // match all records instead of the first one (default = false) on?: string; // column name to resolve (default = with.primary_key) write_through?: boolean; // sync the change to the original data (default = false) affect_original?: boolean; // alias for `write_through` populate?: boolean; // alias for `expand`};NimbusDBDataResolveOptions
Section titled “NimbusDBDataResolveOptions”Optional configurations for .resolve() method.
export type NimbusDBDataResolveOptions = Partial<{ isolate: boolean; // return an isolated copy of the data after the operation (default = false)}>;