correct way to define Loopback.io belongsTo relationship - loopbackjs

I have a simple has_many-belongst_to relationship between 2 Loopback models:
{
"name": "ApiUser",
"base": "PersistedModel",
"idInjection": true,
"options": {
"postgresql": {
"table": "users"
},
"validateUpsert": true
},
"properties": {
"id": {
"type": "string",
"id": true,
"required": true,
"defaultFn": "uuid",
"postgresql": {
"dataType": "uuid"
}
},
"email": {
...
and
{
"name": "ShopifyAccount",
"base": "PersistedModel",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {
"api_key": {
"type": "string",
"required": true
},
"password": {
"type": "string",
"required": true
}
},
"validations": [],
"relations": {
"orders": {
"type": "hasMany",
"model": "ShopifyOrder",
"foreignKey": ""
},
"user": {
"type": "belongsTo",
"model": "ApiUser",
"foreignKey": "userid"
}
},
"acls": [],
"methods": {}
}
When I run automigration, the shopifyaccount table is created, but it looks weird:
Column | Type | Modifiers
-------------------+---------+-------------------------------------------------------------
api_key | text | not null
password | text | not null
id | integer | not null default nextval('shopifyaccount_id_seq'::regclass)
userid | uuid |
apiuserid | uuid |
Indexes:
"shopifyaccount_pkey" PRIMARY KEY, btree (id)
Why did it create 2 columns named like this? Even if I try to specify that foreignkey is "userid", it will still create the apiuserid column. The insert will never update the apiuserid column but it will update the userid column. And then at join time, it will try to join on apiuserid. What am I doing wrong?

So... it seems that the "foreignkey" needs to be specified in both places, in ApiUser and in ShopifyAccount:
{
"name": "ApiUser",
"base": "PersistedModel",
"idInjection": true,
"options": {
"postgresql": {
"table": "users"
},
"validateUpsert": true
},
"properties": {
"id": {
"type": "string",
"id": true,
"required": true,
"defaultFn": "uuid",
"postgresql": {
"dataType": "uuid"
}
},
"email": {
"type": "string",
...
"relations": {
"shopifyAccounts": {
"type": "hasOne",
"model": "ShopifyAccount",
"foreignKey": "userid"
}
},
"acls": [],
"methods": {}
}

Related

Loopback hasManyThrough relation for user

I have such models:
Team
{
"name": "Team",
"plural": "teams",
"base": "PersistedModel",
"idInjection": true,
"options": {
"validateUpsert": true
},
"mixins": {
"ModelRest": {}
},
"hidden": [
"deleted"
],
"filtered": [
"userId",
"archived"
],
"properties": {
"name": {
"type": "string",
"required": true
},
"createdAt": {
"type": "date"
},
"deleted": {
"type": "boolean"
}
},
"validations": [],
"relations": {
"projects": {
"type": "hasMany",
"model": "Project"
},
"user": {
"type": "belongsTo",
"model": "user"
},
"users": {
"type": "hasMany",
"model": "User",
"foreignKey": "",
"through": "TeamMember"
}
},
"acls": [],
"methods": {}
}
TeamMember
{
"name": "TeamMember",
"plural": "team-members",
"base": "Model",
"idInjection": false,
"options": {
"validateUpsert": true
},
"properties": {},
"validations": [],
"relations": {
"user": {
"type": "belongsTo",
"model": "user"
},
"team": {
"type": "belongsTo",
"model": "Team"
}
},
"acls": [],
"methods": {}
}
user
{
"name": "user",
"plural": "users",
"base": "User",
"idInjection": true,
"mixins": {
"ModelRest": {}
},
"hidden": [
"realm",
"emailVerified",
"lastIP",
"deleted",
"utmSource",
"utmMedium",
"utmCampaign"
],
"readOnly": [
"statusId",
"lastListId",
"teamId",
"subscriptionStart",
"subscriptionExpiration",
"apiKey"
],
"properties": {
"name": {
"type": "string",
"required": true,
"mysql": {
"columnName": "username"
}
},
"password": {
"type": "string",
"required": true,
"min": 5
},
"email": {
"type": "string",
"required": true
},
"createdAt": {
"type": "date"
},
"updatedAt": {
"type": "date"
},
"subscriptionStart": {
"type": "date"
},
"subscriptionExpiration": {
"type": "date"
},
"teamId": {
"type": "number"
},
"sharePlan": {
"type": "boolean"
},
"shareLeads": {
"type": "boolean"
},
"timezone": {
"type": "string"
},
"utmSource": {
"type": "string"
},
"utmMedium": {
"type": "string"
},
"utmCampaign": {
"type": "string"
},
"lastIP": {
"type": "string"
},
"deleted": {
"type": "boolean"
}
},
"validations": [],
"relations": {
"team": {
"type": "belongsTo",
"model": "Team"
},
"plan": {
"type": "belongsTo",
"model": "Plan"
},
"billingCycle": {
"type": "belongsTo",
"model": "BillingCycle"
},
"card": {
"type": "belongsTo",
"model": "Card"
},
"lastList": {
"type": "belongsTo",
"model": "List"
},
"status": {
"type": "belongsTo",
"model": "Status"
},
"accessTokens": {
"type": "hasMany",
"model": "AccessToken"
}
},
"acls": [],
"methods": {}
}
I've created relation in Team model:
"users": {
"type": "hasMany",
"model": "User",
"foreignKey": "",
"through": "TeamMember"
}
But users relation in Team doesn't work at all. In API explorer I see
GET /teams/{id}/user
there is no
GET /teams/{id}/users
Why does this happen?
I've even created this relation with Loopback relation generator. Same result. Can't figure out where is the error. Loopback doest see this relation.
Thanks for any help.
It's all, because in model-config.json I have
"TeamMember": {
"dataSource": null,
"public": true
},
instead of:
"TeamMember": {
"dataSource": "db",
"public": true
},

Loopback: How to define a property with an array of strings in Loopback?

I have the following model in a loopback application, that will be persisted in a MongoDB:
Model
Name Coffeshop:
Id
Name (string)
City (String)
Question:
Now i want to be able to store a list of strings in a new property called "tags":
Tags (Array of string)
There is no relation to other models necessary. I need just a plain flat list of strings.
How can i achieve this?
Code:
{
"name": "CoffeeShop",
"plural": "CoffeeShops",
"base": "PersistedModel",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {
"name": {
"type": "string",
"required": true
},
"city": {
"type": "string",
"required": true
}
},
"validations": [],
"relations": {},
"acls": [],
"methods": {}
}
Thats easy:
{
"name": "CoffeeShop",
"plural": "CoffeeShops",
"base": "PersistedModel",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {
"name": {
"type": "string",
"required": true
},
"city": {
"type": "string",
"required": true
},
"tags": {
"type": [
"string"
],
"required": false
}
},
"validations": [],
"relations": {},
"acls": [],
"methods": {}
}

Remove pk in the loopback swagger

In loopback, how could I remove the PK from the swagger json displayed.
This is the json displayed in my swagger:
{
"user_id": "string",
"order_type": "string",
"date": "2016-04-28",
"payload": {
"id": 0
},
"id": 0
}
image detail- Swagger
how could I remove the "id": 0 ?
This is my order.json :
{
"name": "Order",
"plural": "Orders",
"base": "Model",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {
"user_id": {
"type": "string",
"required": true
},
"order_type": {
"type": "string",
"required": true
},
"date": {
"type": "date",
"required": true
},
"payload": {
"type": "Payload",
"required": true
}
},
"validations": [],
"relations": {},
"acls": [],
"methods": {}
}
This is my order.js:
module.exports = (Order) => {
Order.create = function(body, cb) {
//
}
Order.remoteMethod('create', {
'http': {'path': '/'},
'accepts': [
{'arg': 'body', 'type': 'Order', 'required': true, 'http': { 'source': 'body' } }
]
});
};
Hidden property did the trick
{
"name": "Order",
"plural": "Orders",
"base": "Model",
"idInjection": false,
"options": {
"validateUpsert": true
},
"properties": {
...
},
"validations": [],
"relations": {},
"acls": [],
"methods": {},
"hidden": ["id"]
}

scope in inherited model

I have a contact db table and model. Employee model inherits from contact.
If i do GET employees/ it returns all the contacts.
How should I set up my employee.json if I want to return only the contacts with partnerId = 1?
{
"name": "employee",
"base": "contact",
"strict": false,
"idInjection": false,
"options": {
"validateUpsert": true,
"postgresql": {
"schema": "public",
"table": "contact"
}
},
"scope": {
"where": {
"partnerId": 1
}
},
//...
}
Debug says calling GET employees/ makes the following query:
SELECT "name", "position", "email", "password", "id" FROM "public"."contact" ORDER BY "id"
It does not seem that scope is added.
models/partner.json
{
"name": "partner",
// ...
"properties": {
"name": {
"type": "string",
"required": true
},
// ...
},
"validations": [],
"relations": {
"contacts": {
"type": "hasMany",
"model": "contact"
}
//...
},
"acls": [],
"methods": {}
}
Try using the where filter, either in the REST API
/employees?filter[where][partnerId]=1
or in your Employee.js
Employee.find({ where: {partnerId:1} });
https://docs.strongloop.com/display/APIC/Where+filter

Dual belongsTo relations with loopback

I have a couple relations I want to model,
A Message belongs to 2 Profile's (a sender and a recipient)
An Enrollment consists of a Profile and a Curriculum.
I tried to do #1 using 2 hasOne but ended up with Profile.messageId.
{
"name": "Message",
"base": "PersistedModel",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {
"id": {
"type": "number",
"id": true,
"required": true
},
"text": {
"type": "string",
"required": true
},
"created": {
"type": "date",
"required": true
},
"seen": {
"type": "boolean",
"required": true
}
},
"validations": [],
"relations": {
"sender": {
"type": "hasOne",
"model": "Profile",
"foreignKey": ""
},
"recipient": {
"type": "hasOne",
"model": "Profile",
"foreignKey": ""
}
},
"acls": [],
"methods": []
}
Same problem w/ #2...
{
"name": "Enrollment",
"base": "PersistedModel",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {
"id": {
"type": "number",
"id": true,
"required": true
},
"created": {
"type": "date",
"required": true
},
"currentPage": {
"type": "string",
"comments": "What page are they on in this curriculum?"
}
},
"validations": [],
"relations": {
"curriculums": {
"type": "hasOne",
"model": "Curriculum",
"foreignKey": ""
},
"profiles": {
"type": "hasOne",
"model": "Profile",
"foreignKey": ""
}
},
"acls": [],
"methods": []
}