Loopback relations - javascript

Hi I'm trying this example
https://docs.strongloop.com/display/public/LB/HasAndBelongsToMany+relations
I have these two models :
Part
{
"name": "Part",
"base": "PersistedModel",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {
"partNumber": {
"type": "number"
}
},
"validations": [],
"relations": {
"parts": {
"type": "hasAndBelongsToMany",
"model": "Assembly",
"foreignKey": ""
}
},
"acls": [],
"methods": {}
}
Assembly
{
"name": "Assembly",
"base": "PersistedModel",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {
"name": {
"type": "string"
}
},
"validations": [],
"relations": {
"parts": {
"type": "hasAndBelongsToMany",
"model": "Part",
"foreignKey": ""
}
},
"acls": [],
"methods": {}
}
When I try to add a element in assembly I have a undefined element.
I'm using
assembly.js
Assembly.parts.add(part, function(err) {
...
});
but assembly.parts is undefined.
What am I doing wrong?
Thanks

You used a static method on Assembly that is wrong.
Relation methods should used as prototype methods. That make sense.
So you can call like this :
assembly_instance.parts.add(...

Related

Strapi: trouble populating multi-valued attribute for nested relation

I have a collection called dish-category which contains many dishes, and a dish collection that contains many dish-options (another collection).
the list of dishes from each dish-category is available in the API but the nested collection of dish options from each dish is not available on strapi.
the following are the settings for my models:
dish-category.settings.json:
{
"kind": "collectionType",
"collectionName": "dish_categories",
"info": {
"name": "DishCategory",
"description": ""
},
"options": {
"increments": true,
"timestamps": true,
"draftAndPublish": true
},
"pluginOptions": {},
"attributes": {
"Name": {
"type": "string"
},
"Description": {
"type": "text"
},
"dishes": {
"collection": "dish",
"via": "dish_category"
}
}
}
dish.settings.json:
{
"kind": "collectionType",
"collectionName": "dishes",
"info": {
"name": "Dish",
"description": ""
},
"options": {
"increments": true,
"timestamps": true,
"draftAndPublish": true
},
"pluginOptions": {},
"attributes": {
"Name": {
"type": "string"
},
"Description": {
"type": "text"
},
"Total": {
"type": "decimal",
"min": 0,
"required": false,
"default": 0
},
"dish_categories": {
"collection": "dish-category"
},
"dish_options": {
"collection": "dish-option",
"via": "dish"
},
"dish_category": {
"via": "dishes",
"model": "dish-category"
}
}
}
dish-option.settings.json:
{
"kind": "collectionType",
"collectionName": "dish_options",
"info": {
"name": "DishOption",
"description": ""
},
"options": {
"increments": true,
"timestamps": true,
"draftAndPublish": true
},
"pluginOptions": {},
"attributes": {
"Name": {
"type": "string"
},
"Price": {
"type": "decimal",
"min": 0,
"default": 0
},
"dish": {
"via": "dish_options",
"model": "dish"
}
}
}
on the dish-category/controllers/dish-category.js file I tried populating the attribute:
'use strict';
/**
* Read the documentation (https://strapi.io/documentation/developer-docs/latest/development/backend-customization.html#core-controllers)
* to customize this controller
*/
module.exports = {
async find(params, populate){
return strapi.query('dish-category').find(params, ["dishes","dish.dish_options"]);
}
};
I am having trouble displaying nested relations with multiple values, I have tried looking up solutions online, I came across this thread https://forum.strapi.io/t/simple-nested-array-issue/1045/4 but the solution doesn't work for me and it seems like the link to the example is no longer available.

Creating a LoopBack model with a complex data-type

I'm trying to create a model in LoopBack API, the model's JSON widget.json file is:
{
"name": "widget",
"plural": "widgets",
"base": "PersistedModel",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {
"id": {
"type": "string",
"default": null
},
"projectId": {
"type": "string",
"default": null
},
"clientId":{
"type":"string",
"required":false
},
"createdOn": {
"type": "date",
"defaultFn": "now"
},
"updatedOn": {
"type": "date",
"defaultFn": "now"
},
"deletedOn": {
"type": "date",
"default": null
},
"type":{
"type": "string",
"default": null
},
"version":{
"type": "string",
"default":null
},
"dataSource":{
"type": "dataSource"
}
},
"validations": [],
"acls": [],
"methods": {},
"mixins": {
"Timestamps": true
}
}
The problem is that the property:
dataSource
is an object, I tried to declare it in the widget.js file:
'use strict';
const ModelBuilder = require('loopback-datasource-juggler').ModelBuilder;
const modelBuilder = new ModelBuilder();
const dataSource = modelBuilder.define('dataSource', {
endpoint: String,
params: [String],
query: String,
});
When I run the code, I'm getting this error:
Swagger: skipping unknown type "dataSource".
I also tried to find a way to decalare that type as a definition in the same way we do when declaring a swagger file, but I couldn't find!
any ideas or suggestions?
I solved it by declaring the dataSource as the following:
"dataSource":{
"type": {
"endpoint": "string",
"params": ["string"],
"query": "string"
}
}

Loopback 3.x - User Role M:M relation though RoleMapping

I have a custom User, Role and RoleMapping, named AdminUser, AdminRole and AdminRoleMapping. I have populated the db with data, and I am using Mysql and Loopback 3.19. My model configuration is:
{
"name": "AdminRole",
"plural": "adminRoles",
...
"base": "Role",
"relations": {
"users": {
"type": "hasMany",
"model": "AdminUser",
"foreignKey": "principalId",
"through": "AdminRoleMapping"
}
},
...
}
{
"name": "AdminUser",
"plural": "adminUsers",
"base": "User",
...
"roles": {
"type": "hasMany",
"model": "AdminRole",
"foreignKey": "principalId",
"through": "AdminRoleMapping"
}
},
...
}
{
"name": "AdminRoleMapping",
"description": "Map principals to roles",
"plural": "adminRoleMappings",
"base": "RoleMapping",
....
"relations": {
"principal": {
"type": "belongsTo",
"model": "AdminUser",
"foreignKey": "principalId"
},
"roles": {
"type": "belongsTo",
"model": "AdminRole",
"foreignKey": "roleId"
}
},
....
}
When I try to access GET /adminUsers/{id}/roles then I get status error 500
"message": "Relation \"adminRole\" is not defined for AdminRoleMapping model"
What is wrong with my setup? I have followed the docs.
After a bit of trial and error, renaming the relation names in the intermediate table, fixed the issue:
{
"name": "AdminRoleMapping",
"description": "Map principals to roles",
"plural": "adminRoleMappings",
"base": "RoleMapping",
...
"relations": {
"adminUser": {
"type": "belongsTo",
"model": "AdminUser",
"foreignKey": "principalId"
},
"adminRole": {
"type": "belongsTo",
"model": "AdminRole",
"foreignKey": "roleId"
}
},
...
}

Loopback and MongoDB

I've been trying to create a collection that contains an array of objects in loopback.
I want a store data formatted like this:
{
id: "16356135616aaasad", //autogenerated by mongo
"name" : "a name",
"valores": [
{"valor": 567, "fecha": "2016-08-18T00:00:00.000Z"},
{"valor": 569, "fecha": "2016-08-19T00:00:00.000Z"},
...
]
}
I have the following configuration in loopback:
indicador.json
{
"name": "Indicador",
"plural": "indicadores",
"base": "PersistedModel",
"idInjection": true,
"options": {
"validateUpsert": true,
"autoId": true
},
"properties": {
"nombre": {
"type": "string",
"required": true
}
},
"relations": {
"historico": {
"type": "embedsMany",
"model": "Valor"
}
}
}
this is a base collection associated to another model (not persistent)
valor.json
{
"name": "Valor",
"plural": "valores",
"base": "Model",
"properties": {
"valor": {
"type": "number",
"required": true
},
"fecha": {
"type": "date",
"required": true
}
}
}
The problem it's when i try to send a post to the endpoint. If i send this data
{
"nombre": "UF",
"valores": [
{
"valor": 0,
"fecha": "2016-08-18"
}
]
}
The API responses this:
{
"error": {
"name": "ValidationError",
"status": 422,
"message": "The `Indicador` instance is not valid. Details: `valores` contains invalid item at index `0`: `id` is blank (value: [ { valor: 0, fecha: 2016...} ]).",
"statusCode": 422,
"details": {
"context": "Indicador",
"codes": {
"valores": [
"invalid"
]
},
"messages": {
"valores": [
"contains invalid item at index `0`: `id` is blank"
]
}
},
"stack": "ValidationError: The `Indicador` instance is not valid. Details: `valores` contains invalid item at index `0`: `id` is blank (value: [ { valor: 0, fecha: 2016...} ]).\n at /home/dev/app/node_modules/loopback-datasource-juggler/lib/dao.js:322:12\n at ModelConstructor.<anonymous> (/home/dev/app/node_modules/loopback-datasource-juggler/lib/validations.js:492:11)\n at ModelConstructor.next (/home/dev/app/node_modules/loopback-datasource-juggler/lib/hooks.js:81:12)\n at ModelConstructor.<anonymous> (/home/dev/app/node_modules/loopback-datasource-juggler/lib/validations.js:489:23)\n at ModelConstructor.trigger (/home/dev/app/node_modules/loopback-datasource-juggler/lib/hooks.js:71:12)\n at ModelConstructor.Validatable.isValid (/home/dev/app/node_modules/loopback-datasource-juggler/lib/validations.js:455:8)\n at /home/dev/app/node_modules/loopback-datasource-juggler/lib/dao.js:318:9\n at doNotify (/home/dev/app/node_modules/loopback-datasource-juggler/lib/observer.js:98:49)\n at doNotify (/home/dev/app/node_modules/loopback-datasource-juggler/lib/observer.js:98:49)\n at doNotify (/home/dev/app/node_modules/loopback-datasource-juggler/lib/observer.js:98:49)"
}
}
¿Why i get this error?
The id inside the objects of the array that I need isn't necessary for me. I don't understand why happen this.
You need to specify that embedded model doe not need id
"relations": {
"historico": {
"type": "embedsMany",
"model": "Valor",
"options": {
"forceId": false,
"validate": true,
"persistent": false
}
}
}
You need to add "defaultFn":"uuid" to the id property in the json of the model that is going to be embeded in order to have the id generated. In your case it will look like the following:
{
"name": "Valor",
"plural": "valores",
"base": "Model",
"properties": {
"id":{
"type": "string",
"defaultFn":"uuid",
"id":true
},
"valor": {
"type": "number",
"required": true
},
"fecha": {
"type": "date",
"required": true
}
}
}

Strongloop property from relation in parent

I don't know if I'm just blind or something but how can I do the following:
I have a User model with a hasOne relation to a UserData model. I only want one property of UserData directly in the results of User.
The relation in User looks like this:
"relations": {
"userData": {
"type": "hasOne",
"model": "UserData"
}
}
And the default scope in User:
"scope": {
"include": "userData"
}
So the result for one User is:
[
{
"id": 5,
"email": "example#example.com",
"name": "Example",
"userData": {
"id": 5,
"birthdate": "1971-09-06T00:00:00.000Z"
}
}
]
But what I want is this:
[
{
"id": 5,
"email": "example#example.com",
"name": "Example",
"birthdate": "1971-09-06T00:00:00.000Z"
}
]
How can I achive this?
Edit:
The two model definitions:
ChiliUser:
{
"name": "ChiliUser",
"base": "ChiliUserData",
"idInjection": true,
"options": {
"validateUpsert": true,
"mysql": {
"table": "person"
}
},
"properties": {
"id": {
"type": "number"
},
"email": {
"type": "string"
},
"password": {
"type": "string"
},
"vorname": {
"type": "string"
},
"name": {
"type": "string"
},
"spitzname": {
"type": "string"
},
"strasse": {
"type": "string"
},
"plz": {
"type": "number"
},
"ort": {
"type": "string"
},
"geolat": {
"type": "string"
},
"geolng": {
"type": "string"
}
},
"validations": [],
"relations": {},
"acls": [],
"methods": []
}
ChiliUserData:
{
"name": "ChiliUserData",
"base": "PersistedModel",
"idInjection": true,
"options": {
"validateUpsert": true,
"mysql": {
"table": "person_data"
}
},
"properties": {
"id": {
"type": "number"
},
"person_id": {
"type": "number"
},
"birthdate": {
"type": "date"
}
},
"validations": [],
"relations": {},
"acls": [],
"methods": []
}
Are you using the built-in User model? If you are, you can simply extend it with your UserData model using base: "User", and the underlying schema will be as you desire:
{
"name": "UserData",
"base": "User",
"properties": {}
...
}
But this setup would mean you'd use UserData over User in your code. Since the built-in User model gets in the way, I'd recommend a different word like Person or Customer, in which case it would look like:
{
"name": "Person",
"base": "User",
"properties": {
...extra user data properties only...
}
...
}
This way, only Person will have all the extra "user data" fields on it, but will also include all the fields/methods defined for User inside node_modules/loopback/common/models/User.json. If you're using MySQL, the Person table will be created with the combination of fields from both User and Person.

Categories