Custom junction table in strapi - node.js

I have recently started working on strapi and was looking at the relations inside model in their documentation. My scenario is as follows. I have a model named course and another named tag. They have many to many relationship between them.This is what ./api/course/models/course.settings.json has when I made the relation between them named as tag2.
{
"connection": "default",
"collectionName": "course",
"info": {
"name": "course"
},
"options": {
"increments": true,
"timestamps": true
},
"attributes": {
"image_link": {
"type": "string"
},
"created_by": {
"columnName": "created_by_id",
"plugin": "users-permissions",
"model": "user"
},
"updated_by": {
"columnName": "updated_by_id",
"plugin": "users-permissions",
"model": "user"
},
"title": {
"type": "string"
},
"short_description": {
"type": "text"
},
"slug": {
"type": "string",
"unique": true
},
"tags2": {
"collection": "tag",
"via": "courses",
"dominant": true
}
}
}
When I specify the relation using the admin panel strapi itself made a junction table named as courses_tags_2_s__tags_courses.
Here is what tag model looks like
{
"connection": "default",
"collectionName": "tag",
"info": {
"name": "tag",
"mainField": "ui_label"
},
"options": {
"increments": true,
"timestamps": true
},
"attributes": {
"code": {
"type": "string"
},
"description": {
"type": "string"
},
"created_by": {
"plugin": "users-permissions",
"model": "user",
"columnName": "created_by_id"
},
"updated_by": {
"plugin": "users-permissions",
"model": "user",
"columnName": "updated_by_id"
},
"ui_label": {
"type": "string"
},
"courses": {
"via": "tags2",
"collection": "course"
}
}
}
I have a couple of questions
1) Is there a way I can set up the junction table as courses_tags ? i.e overriding the strapi one
2) I have set my mainField as "ui_label" in tag.settings.json but in the admin panel while editing course table content(rows in course table), in the related field of tag2 I see "code" field shown there instead of "ui_label". How to set the mainField?
Note: I have setup strapi with mysql server.

so to answer your first question, there is currently no way to override the join table between two models. This is totally auto-generated by Strapi.
For the second question, this part of the docs is out to date.
To manage display information you will have to use the content manager configuration in the admin panel.
Here a short video - https://www.youtube.com/watch?v=tzipS2CePRc&list=PL7Q0DQYATmvhlHxHqfKHsr-zFls2mIVTi&index=5&t=0s

For 1) Is there a way I can set up the junction table as courses_tags ? i.e overriding the strapi one:
You can specify the following option:
"collectionName": "courses_tags"

Related

Unexpected __data in mongodb loopback v3

Why my database has field __data that exactly copying the real data but wouldn't update if the data is changed?
Here is the example of the data :
{
"id": ObjectId("600ffdf0317f9617960b7df6"),
"userId" : "bf959bb8-78a6-426b-b372-cf5a1f9ef731",
"name": "Product 1",
"isActive": true,
"createdAt": ISODate("2021-05-26 11:33:04.992Z"),
"updatedAt": null,
"__data": {
"id": "600ffdf0317f9617960b7df6",
"userId" : "bf959bb8-78a6-426b-b372-cf5a1f9ef731",
"name": "Product 1",
"isActive": true,
"createdAt": ISODate("2021-05-26 11:33:04.992Z"),
"updatedAt": null,
},
}
when I update the data lets say, {"name": "Product 1 New"}, but the "__data.name" still "Product 1"
The problem is when I get the data using find() or findById(), the result is showing "Product 1" which is get from the __data instead of the real data.
I'm using loopback v3 and using mongodb for the database.
Below is my schema for product.
product.json
{
"name": "products",
"base": "PersistedModel",
"plural": "products",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {
"id": {
"type": "string",
"id": true
},
"userId": {
"type": "string"
},
"name": {
"type": "object"
},
"isActive": {
"type": "boolean",
"default": false
},
"createdAt": {
"type": "date",
"default": "$now"
},
"updatedAt": {
"type": "date",
"default": "$now"
},
},
"validations": [],
"relations": {
"user": {
"type": "belongsTo",
"model": "reseller",
"foreignKey": "userId"
}
},
"acls": [
],
"scope": {
"order": ["createdAt DESC"]
},
"methods": {}
}
How to solve this?
I want to get the response is the real data which is the updated one, and how to avoid to have field __data?
In case somebody stumbled on this even though LB3 is pretty much dead and IBM is trying to kill off LB4.
My problem was the difference between update() and updateAll(), updateAll() seem to add the data object in mongodb not sure why or how if change to update() is should be fine.

Loopback join/include two collections

I would like to include my product_product model inside product_template.
1 - Each product template has its own product_product variations "HasMany" .
2 - product_product has only one template "BelongsTo" product_template
3- product_template should be filled with only related product_product variations.
4- The two models are saved seprately, so when I call for find() function I would like to get a product_template model filled with the product_product related to it (Could be more than one)
Get product template function :
Producttemplate.find({
include: {
relation: 'variations',
scope: {
fields: ['sku', 'name', 'price', 'regular_price', 'weight', 'description', 'stock_quantity'],
},
},
})
product_product Model :
This model should be included in the product_template
{
"name": "product_product",
"base": "PersistedModel",
"strict": true,
"options": {
"validateUpsert": true
},
"properties": {
"_id_Odoo": {
"type": "number"
},
"sku": {
"type": "string",
"id": true,
"required": true,
"description": "Yes it's SKU"
},
#fields
},
"validations": [],
"relations": {
"product": {
"type": "belongsTo",
"model": "product_template",
"foreignKey": "_id_Odoo"
}
},
"acls": [],
"methods": {}
}
product_template Model :
This model should include the product_product
{
"name": "product_template",
"base": "PersistedModel",
"strict": true,
"options": {
"validateUpsert": true
},
"properties": {
"_id_Odoo": {
"type": [
"number"
]
}
"sku": {
"type": "string",
"id": true,
"required": true,
"description": "Yes it's SKU"
},
"name": {
"type": "string"
}
},
"scope": {
"include": "variations"
},
"hidden": ["_id_Odoo"],
"validations": [],
"relations": {
"variations": {
"type": "hasMany",
"model": "product_product",
"foreignKey": "_id_Odoo"
}
},
"acls": [],
"methods": {}
}
Result :
This the result of get product template above :
{ sku: 'AHWLI05942-FUSCHIA', variations: List [] },
{ sku: 'AHWLI05943-BLACK', variations: List [] },
{ sku: 'AHWLI05943-BURGUNDY', variations: List [] },
{ sku: 'AHWLI05944-BLACK', variations: List [] },
{ sku: 'AHWLI05944-MARRON', variations: List [] },
{ sku: 'AHWLI05945-BLUE', variations: List [] }
When I point into variations i get a function and into variations.list i get undefined any ideas how to get exact structure ?
example code part of my model "TeamRole" which belongsTo "Team" and User" in model level.
teamRole.json
"validations": [],
"relations": {
"team": {
"type": "belongsTo",
"model": "Team",
"foreignKey": ""
},
"user": {
"type": "belongsTo",
"model": "User",
"foreignKey": ""
}
}
Example search query for team role,
query.js
app.models.TeamRole.find({
where: {
userId: user.id
},
include: {
relation: 'team'
}
},function(err,teams){
console.log("teams will have all the include teams[] with team role ")
});
Hope using above example will help you.
sorry for late response, it was just misunderstanding of the relation and structure, i made a function that verifies if the product model exists in the template if yes, i push the template id in the product model and it worked fine.
product_product Model : I deleted the relation in the model below because it's useless, so i removed id property in sku and removed _id_Odoo field, then i added id field and parent_template field that contains the template model id.
{
"name": "product_product",
"base": "PersistedModel",
"strict": true,
"options": {
"validateUpsert": true
},
"properties": {
"id": {
"type": "number"
"id": true
}
"parent_template": {
"type": "number"
},
"sku": {
"type": "string",
"required": true,
"description": "Yes it's SKU"
},
#fields
}
product_template Model : I removed the _id_odoo and id property in sku and created an id for this model and in relation i made parent_template as foreignkey
{
"name": "product_template",
"base": "PersistedModel",
"strict": true,
"options": {
"validateUpsert": true
},
"properties": {
"id": {
"type": "number",
"id" : true
}
"sku": {
"type": "string",
"required": true,
"description": "Yes it's SKU"
},
"name": {
"type": "string"
}
},
"scope": {
"include": "variations"
},
##########
"relations": {
"variations": {
"type": "hasMany",
"model": "product_product",
"foreignKey": "parent_template"
}
},
#############
}

Two relations from same model loopback not working

I have two models users and appointments.
The users model is like below-
{
"users": {
"0": {
"id": "1",
"name": "test1",
"role": "doctor"
},
"1": {
"id": "2",
"name": "test2",
"role": "patient"
},
"2": {
"id": "3",
"name": "test3",
"role": "support"
}
}
}
Now in the above model , if the role is doctor , we are calling it as doctor_id , if patient then patient_id and so on.
Now my appointment model is below->
{
"name": "appointments",
"plural": "appointments",
"base": "PersistedModel",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {
"appointmentDate": {
"type": "date"
},
"appointmentTime": {
"type": "string"
},
"doctorId": {
"type": "string"
},
"patientId": {
"type": "string"
}
},
"validations": [],
"relations": {
"Doctor": {
"type": "belongsTo",
"model": "users",
"foreignKey": "doctorId"
},
"Patient": {
"type": "belongsTo",
"model": "users",
"foreignKey": "patientId"
}
},
"acls": [],
"methods": {}
}
So when i try to GET all appointments , it is not sending the relation data from users. If i add single relation it work as expected , but not working with multiple relations from same model.
Thanks in advance,
Including my previous comment to give context:
The way I did it, I believe foreignkey should be "" for both. You should not define doctorId and patientId and you probably have to define two hasMany relations in you user class with foreign key "Doctor" and "Patient"
To give an example here are the relations defined in my user class (called customer)
"commentsWritten": {
"type": "hasMany",
"model": "comment",
"foreignKey": "sourceCustomerId"
},
"commentsReceived": {
"type": "hasMany",
"model": "comment",
"foreignKey": "targetCustomerId"
},
then in my comment definition I have the following
"properties": {
...
"targetCustomerId": {
"type": {
"required": true
}
},
"sourceCustomerId": {
"type": {
"required": true
}
}
},
"relations": {
"targetCustomer": {
"type": "belongsTo",
"model": "customer",
"foreignKey": ""
},
"sourceCustomer": {
"type": "belongsTo",
"model": "customer",
"foreignKey": ""
}
},
Please note, that I did define the properties (ids) but, if I remember correctly, it was only so I could force them to be not null, i.e. you should not need it.
If you go to the belongsTo documentation you can see that the foreignKey field is empty, so you need to remove it from your relations definition.
You probably also want to define the other side of the relation.
I.e. define a hasMany relation users hasMany appointments:
{
"name": "users",
"base": "PersistedModel",
...
"relations": {
"doctors": {
"type": "hasMany",
"model": "appointments",
"foreignKey": "doctorId"
},
"patients": {
"type": "hasMany",
"model": "appointments",
"foreignKey": "patientId"
},
...
}
However, what you are trying to do might not be supported (and in fact I'm not even sure if it makes sense for LoopBack).
You can check the documentation on polymorphic relations and even though it's a work in progress there's no mention of having Model A hasMany Model B through more than one foreignKey at the same time.
LoopBack would need to have some logic to search under the first foreign key and if nothing is found then searching under the other foreign key, and I'm not sure if this complex composition is supported.
Suggestion
Why not define two models, one for Doctors and one for Patients and have two different relations instead? You can even go to the documentation on HasManyThrough relations and you can see an example that models something very similar to what you are trying to do.

How do I get Loopback to prefer short ids when doing id injection?

I have a loopback app which gives ids like "56dbfa7089223aca7946ca14" when creating models. I would prefer ids like "0" or "73". Is there a way to adjust id-injection practices to have ids start at 0 and increment as base-10 integers?
The data store is MongoDB v2.6.10)
running loopback v2.22 on node v5.7.1 on Ubuntu 15.10
Here's the relevant model.json
{
"name": "Term",
"base": "PersistedModel",
"idInjection": true,
"options": {
"validateUpsert": true
},
"properties": {
"name": {
"type": "string",
"required": true
},
"beginDate": {
"type": "date",
"required": true
},
"endDate": {
"type": "date",
"required": true
}
},
"validations": [],
"relations": {
"lessons": {
"type": "hasMany",
"model": "Lesson",
"foreignKey": ""
},
"classes": {
"type": "hasMany",
"model": "Class",
"foreignKey": ""
},
"weeklySchedules": {
"type": "hasMany",
"model": "WeeklySchedule",
"foreignKey": ""
}
},
"acls": [],
"methods": {}
}
there are several ways to do it, you can read about them in official documentation
It is stated by mongo developers, that is completely ok, to use your own id, if you really need it, so go for it.
However if you do it only because you "dont want ObjectId, because it does not look good", I suggest you, to get used to it.

Add the current user before store a model strongloop

I recently start with Strongloop framework,
I made a simple model
{
"name": "income",
"plural": "incomes",
"base": "PersistedModel",
"idInjection": true,
"properties": {
"description": {
"type": "string",
"required": true
},
"amount": {
"type": "number",
"required": true
},
"when": {
"type": "date",
"required": true
}
},
"validations": [],
"relations": {
"user": {
"type": "belongsTo",
"model": "User",
"foreignKey": ""
}
},
"acls": [],
"methods": []
}
I want make a relation with current session user and the income record. but I can't find a example for that.
You can use the current context, there is a code example at the bottom of the link, but you have to expand it:
Link

Resources