Different models of the object with relationships

Hello!

I have a problem with model in relationship

I have Cities and Buildings in Cities

Relationship settings:
City belongs to many Buildings
City has many Buildings

In cities API i see

cities API
{
id: 1,
city_name: "Chicago",
created_at: "2021-01-06T10:11:06.000Z",
updated_at: "2021-01-09T15:50:23.000Z",
building: {
id: 1,
name: "SomeBuilding in City",
created_at: "2021-01-06T10:10:45.000Z",
updated_at: "2021-01-09T15:50:23.000Z",
city: 1
}

In Building API i see

Building API

{
id: 1,
name: “SomeBuilding in City”,
created_at: “2021-01-06T10:10:45.000Z”,
updated_at: “2021-01-09T15:50:23.000Z”,
citys: [
{
id: 1,
name: “Chicago”,
created_at: “2021-01-06T10:11:06.000Z”,
updated_at: “2021-01-09T15:50:23.000Z”,
storage: 1
}
}

Why in cities api in the building model city is only ID of city
But in Buildings api city is model of city?

And how to make api of cities looks like example

example cities API

example

{
id: 1,
city_name: “Chicago”,
created_at: “2021-01-06T10:11:06.000Z”,
updated_at: “2021-01-09T15:50:23.000Z”,
building: {
id: 1,
name: “SomeBuilding in City”,
created_at: “2021-01-06T10:10:45.000Z”,
updated_at: “2021-01-09T15:50:23.000Z”,
citys: [
{
id: 1,
name: “Chicago”,
created_at: “2021-01-06T10:11:06.000Z”,
updated_at: “2021-01-09T15:50:23.000Z”,
storage: 1
}
}

Any ideas?

Related issue: Strapi different models of the object with relationships · Issue #9081 · strapi/strapi · GitHub


Is your project code public so I can take a look at the model/relationship structure?

185.4.75.155:1337/users/
users role is model
185.4.75.155:1337/offices/
users role is ID

One object user have two diferent models

Same problem
185.4.75.155:1337/cities
buildings city is ID
185.4.75.155:1337/buildings
buildings city is model

Demo server
http://185.4.75.155:1337/admin/
user mail@bk.ru
password Test123456

How to make sure the role / city is always either ID or model

It will be best if there is a model everywhere, not an ID

Any ideas?

Ah you are referring to the model population, by default we only populate one level deep. If you need additional population you will need to customize the default controller.

Are you familiar with doing so?

No, unfortunately I’m not familiar, I’m generally not good at nodeJS

For overriding the controllers you can take a look at this document: https://strapi.io/documentation/developer-docs/latest/concepts/controllers.html#concept

But the specific line I’m referring to is this one in the find controller:
entities = await strapi.services.restaurant.find(ctx.query);

Looking at the service documentation here: https://strapi.io/documentation/developer-docs/latest/concepts/services.html#core-services

There is an undefined key that you can customize for the population level.

In your case you can use the following line:
entities = await strapi.services.office.find(ctx.query, [ 'users', 'users.office' ]);

This should give you the expected output such as:

[
  {
    "id": 1,
    "office_name": "Chicago Office",
    "published_at": "2021-01-16T14:15:14.000Z",
    "created_at": "2021-01-16T14:11:30.000Z",
    "updated_at": "2021-01-16T14:15:14.000Z",
    "users": [
      {
        "id": 1,
        "username": "someuser",
        "email": "dsds@maill.ru",
        "provider": "local",
        "confirmed": false,
        "blocked": false,
        "role": 1,
        "created_at": "2021-01-16T14:11:10.000Z",
        "updated_at": "2021-01-16T14:11:32.000Z",
        "office": {
          "id": 1,
          "office_name": "Chicago Office",
          "published_at": "2021-01-16T14:15:14.000Z",
          "created_at": "2021-01-16T14:11:30.000Z",
          "updated_at": "2021-01-16T14:15:14.000Z"
        }
      }
    ]
  }
]

Thank you, It’s helped for me.

I decided to make ID everywhere, not models. But I can’t figure out how to make the user role in the form of an ID, not a model.

In extensions / users-permissions / created the controllers folder
Inside it User.js

And the code is as below:

example
const { sanitizeEntity } = require('strapi-utils');

module.exports = {
  /**
   * Retrieve records.
   *
   * @return {Array}
   */


  async find(ctx) {
    let entities;
    if (ctx.query._q) {
      entities = await strapi.plugins['users-permissions'].services.user.search(ctx.query);
    } else {
      entities = await strapi.plugins['users-permissions'].services.user.find(ctx.query, [ 'role', 'role.user' ]);
    }

    return entities.map(entity => sanitizeEntity(entity, { model: strapi.models.user }));
  },
};

i was tried do this like, but it not works

Depends on which endpoint you mean. If it’s the /users/me one this is the one you need to override:

Specifically the array containing 'role'

endpoint is users
185.4.75.155:1337/users/
Role of users in this endpoint = model, I need ID

Is there any way to do this?

The easiest way to track down what you need to modify is looking at it from this perspective:

You know the route, in your case FIND /users thus we need to look at where that route comes from. We know in this case it’s the users-permissions plugin, and routes are always stored in the config/routes.json Thus:

Specifically what we are looking for is the handler or in this case: "handler": "User.find",. The Handler is a Koa term which for Strapi translates to a controller, the pathing you see there means we are now looking inside of the users-permission’s controller folder. The handler tells us it’s in the User.js file under the find function.

Just like in the previous example I gave you there is a populate variable that could change based on the request:

users = await strapi.plugins['users-permissions'].services.user.fetchAll(ctx.query, populate);

And the specific line here: { populate } = {} states if it isn’t defined, just leave it as an empty object or AKA the default population of 1 level deep.

Much like the previous example I gave you for the /users/me, this service comes from the exact same place just a few lines below:

The same logic applies, if you pass an empty array, nothing will be populated or you include the fields you want populated.