Strapi V4 populate Media and Dynamiczones from Components

Just populate your body{} object , and you will get all components.
Hope this will help someone’s problem

And instead of YourPage add the name of your own page

const { createCoreController } = require("@strapi/strapi").factories;
module.exports = createCoreController(
“api::Yourpage.Your-page”,
({ strapi }) => ({
async find(ctx) {
const { query } = ctx;
const entity = await strapi.entityService.findMany(
“api::yourPage.yourPage”,
{
…query,
populate: {
body: {
populate: “*”,
},
},
}
);
console.log(entity);
const sanitizedEntity = await this.sanitizeOutput(entity, ctx);
return this.transformResponse(sanitizedEntity);
}

Hello, I had an issue for media in a component not populating so added this if you would like to check it over :slight_smile: ?

The below will now populate all components, repeatables and media by calling populate=* on an endpoint.

/*********************************
 * Poplulate All Attributes
 *
 * https://forum.strapi.io/t/strapi-v4-populate-media-and-dynamiczones-from-components/12670/2
 * 
 * Updates
 * Line 24: Added media type handling
 *
 *********************************/

const { createCoreController } = require("@strapi/strapi/lib/factories");
const {
  default: entityService,
} = require("@strapi/strapi/lib/services/entity-service");

const populateAttribute = (attr) => {
  const { components, repeatable } = attr;
  if (components) {
    const populate = components.reduce((currentValue, current) => {
      const [componentDir, componentName] = current.split(".");

      /* Component attributes needs to be explicitly populated */
      const componentAttributes = Object.entries(
        require(`../components/${componentDir}/${componentName}.json`)
          .attributes
      )
        /** Implemented media type */
      const attrPopulates = componentAttributes.filter(([, v]) => {
        return ["component", "media"].includes(v.type)
      }).reduce(
        (acc, [curr, obj]) => { 
          switch (obj.type) {
            case "component" :
                return  { ...acc, [curr]: { populate: "*" } };
            case "media":
                return  { ...acc, [curr]: "*" };
          }
        },
        {}
      );

      return {
        ...currentValue,
        [current.split(".").pop()]: { populate: "*" },
        ...attrPopulates,
      };
    }, {});

    return { populate };
  } else if (repeatable) {
    const componentName = attr.component.split(".")[1];
    const populate = { [componentName]: { populate: "*" } };
    return { populate };
  }
  return { populate: "*" };
};

const getPopulateFromSchema = function (schema) {
  return Object.keys(schema.attributes).reduce((currentValue, current) => {
    const attribute = schema.attributes[current];
    if (!["dynamiczone", "component"].includes(attribute.type)) {
      return { [current]: populateAttribute(attribute) };
    }
    return {
      ...currentValue,
      [current]: populateAttribute(attribute),
    };
  }, {});
};

function createPopulatedController(uid, schema) {
  return createCoreController(uid, () => {

    return {
      async find(ctx) {
        // deeply populate all attributes with ?populate=*, else retain vanilla functionality
        if (ctx.query.populate === "*") {
          ctx.query = {
            ...ctx.query,
            populate: getPopulateFromSchema(schema),
          };
        }
        return await super.find(ctx);
      },
      async findOne(ctx) {
        if (ctx.query.populate === "*") {
          ctx.query = {
            ...ctx.query,
            populate: getPopulateFromSchema(schema),
          };
        }
        return await super.findOne(ctx);
      },
    };
  });
}

module.exports = createPopulatedController;


2 Likes

Hello,

I didn’t find this populated a relation in a component so used and updated Hugofgx9’s solution

I am getting the following error:

Invalid populate field. Expected a relation, got string

My schema is the following:

{
  "kind": "collectionType",
  "collectionName": "page_slices",
  "info": {
    "singularName": "page-slice",
    "pluralName": "page-slices",
    "displayName": "Pages",
    "description": ""
  },
  "options": {
    "draftAndPublish": true
  },
  "pluginOptions": {
    "versions": {
      "versioned": true
    },
    "i18n": {
      "localized": true
    }
  },
  "attributes": {
    "PageName": {
      "type": "string",
      "pluginOptions": {
        "i18n": {
          "localized": true
        }
      }
    },
    "SEO": {
      "type": "component",
      "repeatable": false,
      "component": "shared.seo",
      "pluginOptions": {
        "i18n": {
          "localized": true
        }
      }
    },
    "Slug": {
      "type": "string",
      "pluginOptions": {
        "i18n": {
          "localized": true
        }
      }
    },
    "Module": {
      "type": "dynamiczone",
      "components": [
        "shared.home-hero",
        "shared.home-logos",
        "shared.inner-hero",
        "shared.rich-text-editor",
        "shared.seperator"
      ],
      "pluginOptions": {
        "i18n": {
          "localized": true
        }
      }
    }
  }
}

Any more updates on this? put this in my project and added the controller in my collection controller, doesn’t work.

1 Like

For those still struggling with this, we use this simple customization to the controller find() function for an entity’s dynamic zones and content like below (this entity is a Page we created, so it is the controller for this ./src/api/page/controllers/page.js).
(You will need to augment the populate fields with the names of your own repeatable components or media attributes, and add to it as you add new sub-components to the entity… bit annoying but it has worked so far for our needs…)

async find(ctx) {
    const { query } = ctx;

    const entity = await strapi.entityService.findMany("api::page.page", { // page.page is our entity here
      ...query, // attach any incoming queries already in the request
      populate: {
        Image: true, // get data for media item field called "Image"
        Content: {// a dynamic zone with different components, 
// and those components might have some repeatable sub-component too
// We only seem to need to add the sub-components...
          populate: {
            Image: true,// media field called "Image"
            Buttons: {// repeatable sub-component called "Buttons" used in a dynamic zone component
              populate: {
                page: true,// the Button component has a relation to a page item, so populate that...
              },
            },
            Icons: true,// another repeatable sub-component used in a dynamic zone component
          },
        },
      },
    });
    const sanitizedEntity = await this.sanitizeOutput(entity, ctx);

    return this.transformResponse(sanitizedEntity);
  },
4 Likes

Hello everyone, I am sharing with you my solution for nested relationships. My entity “home-setting” has two attributes of type “media” (“image” and “logo”) and looks like:
“home-setting”: {
“interval”,
“slides”: {
“image”: { … },
“logo”: {…}
}
}.
In my home-setting “services”, when writing only this:

const { createCoreService } = require(’@strapi/strapi’).factories;

module.exports = createCoreService(‘api::home-setting.home-setting’, ({strapi}) =>({
async find(params, module) {
return await strapi.query(‘api::home-setting.home-setting’).findOne({
populate: true
)}
}));

I was able to just fetch a slide, with neither image nor code. Instead, following nextrapi example, I added this lines:

module.exports = createCoreService(‘api::home-setting.home-setting’, ({strapi}) =>({

async find(params, module) {
return await strapi.query(‘api::home-setting.home-setting’).findOne({
populate: {
slides: {
populate: {
image: true,
icon: true
}
}
},
})
}
}));

This works fine for me, with no need of customizing controllers.

Currently using this version of the populate helper:

populate.js
/*********************************
 * Poplulate All Attributes
 *
 * https://forum.strapi.io/t/strapi-v4-populate-media-and-dynamiczones-from-components/12670/2
 *
 * Updates
 * Line 24: Added media type handling
 *
 *********************************/

const { createCoreController } = require("@strapi/strapi/lib/factories");
const {
  default: entityService,
} = require("@strapi/strapi/lib/services/entity-service");

const populateAttribute = (attr) => {
  const { components, repeatable } = attr;
  if (components) {
    const populate = components.reduce((currentValue, current) => {
      const [componentDir, componentName] = current.split(".");

      /* Component attributes needs to be explicitly populated */
      const componentAttributes = Object.entries(
        require(`../components/${componentDir}/${componentName}.json`)
          .attributes
      );
      /** Implemented media type */
      const attrPopulates = componentAttributes
        .filter(([, v]) => {
          return ["component", "media"].includes(v.type);
        })
        .reduce((acc, [curr, obj]) => {
          switch (obj.type) {
            case "component":
              return { ...acc, [curr]: { populate: "*" } };
            case "media":
              return { ...acc, [curr]: "*" };
          }
        }, {});

      return {
        ...currentValue,
        [current.split(".").pop()]: { populate: "*" },
        ...attrPopulates,
      };
    }, {});

    return { populate };
  } else if (repeatable) {
    const componentName = attr.component.split(".")[1];
    const populate = { [componentName]: { populate: "*" } };
    return { populate };
  }
  return { populate: "*" };
};

const getPopulateFromSchema = function (schema) {
  return Object.keys(schema.attributes).reduce((currentValue, current) => {
    const attribute = schema.attributes[current];
    if (!["dynamiczone", "component"].includes(attribute.type)) {
      return { [current]: populateAttribute(attribute) };
    }
    return {
      ...currentValue,
      [current]: populateAttribute(attribute),
    };
  }, {});
};

function createPopulatedController(uid, schema) {
  return createCoreController(uid, () => {
    return {
      async find(ctx) {
        // deeply populate all attributes with ?populate=*, else retain vanilla functionality
        if (ctx.query.populate === "*") {
          ctx.query = {
            ...ctx.query,
            populate: getPopulateFromSchema(schema),
          };
        }
        return await super.find(ctx);
      },
      async findOne(ctx) {
        if (ctx.query.populate === "*") {
          ctx.query = {
            ...ctx.query,
            populate: getPopulateFromSchema(schema),
          };
        }
        return await super.findOne(ctx);
      },
    };
  });
}

module.exports = createPopulatedController;

It is not populating the Team Member relationship at this level:

  • Page - collection
    • Section - dynamic zone
      • Team - component
        • Team Category - repeating component
          • Team Member - relationship field
Current data output
{
  "Sections": [
    // ...other sections here
    {
      "id":1,
      "__component":"sections.team",
      "Title":"The Team",
      "Subtitle":"Your Expert Team",
      "color":"Dark",
      "teamCategory": [
        {
          "id":3,
          "categoryTitle":"Sales & Leasing",
          // Should have teamCategory relation here.
        },
        {
          "id":4,
          "categoryTitle":"Marketing",
          // Should have teamCategory relation here.
        }
      ]
    }
  ]
}

Any help would be great. This is getting very frustrating.

Here’s a modification of @urbandale’s solution, which includes the code for overwriting the findOne controller, and maintains default functionality for API requests which do not include populate=*.

This seems to be the best working solution for v4.1.7.

Please see @urbandale’s post for more context.

./src/api/page/controllers/page.js

'use strict'

/**
 *  page controller
 *
 *  info: https://forum.strapi.io/t/strapi-v4-populate-media-and-dynamiczones-from-components/12670/26
 */

const { createCoreController } = require('@strapi/strapi').factories

// declare the uid for the controller
const uid = 'api::page.page'

// see @urbandale's post for context: https://forum.strapi.io/t/strapi-v4-populate-media-and-dynamiczones-from-components/12670/26
const components = {
  Image: true, // get data for media item field called "Image"
  Content: {
    // a dynamic zone with different components,
    // and those components might have some repeatable sub-component too
    // We only seem to need to add the sub-components...
    populate: {
      Image: true, // media field called "Image"
      Buttons: {
        // repeatable sub-component called "Buttons" used in a dynamic zone component
        populate: {
          page: true, // the Button component has a relation to a page item, so populate that...
        },
      },
      Icons: true, // another repeatable sub-component used in a dynamic zone component
    },
  },
}

module.exports = createCoreController(uid, () => {
  return {
    async find(ctx) {
      // overwrite default populate=* functionality
      if (ctx.query.populate === '*') {
        const entity = await strapi.entityService.findMany(uid, {
          ...ctx.query,
          populate: components,
        })
        const sanitizedEntity = await this.sanitizeOutput(entity, ctx)

        return this.transformResponse(sanitizedEntity)
      }
      // maintain default functionality for all other request
      return super.find(ctx)
    },
    async findOne(ctx) {

      const { id } = ctx.request.params

      if (ctx.query.populate === '*') {
        const entity = await strapi.entityService.findOne(uid, id, {
          ...ctx.query,
          populate: components,
        })
        const sanitizedEntity = await this.sanitizeOutput(entity, ctx)

        return this.transformResponse(sanitizedEntity)
      }

      return super.findOne(ctx)
    },
  }
})

1 Like

As we already know we can populate by field like “/articles?populate=tags,author”. But, if we have a media filed in author table (lets say an ‘avatar’ image) , it will not be returned in response.

To fix this, we can just access it like this, “/articles?populate=tags,author.avatar” where avatar is the media field we want to populate in our nested author object.

I do it for selective populate use cases. Been bummed about it for couple of days and found out this works by trial and error (smashes_head)

6 Likes

this is awesome, thanks… btw if you don’t mind me asking, how did you arrive at this code ? P.S: sorry if this is a stupid question. I am a junior dev :slight_smile:

i found a solution by using this plugin: strapi-plugin-populate-deep - npm
it works like a charm.
using strapi version: 4.1.5
Hope it works for you all. Greetings

5 Likes

I’ve been going through this all week and THIS was the best solution :+1:t2:

1 Like

Thanks @manicho you saved our week :grinning:

Let me add, this is to be installed on your STRAPI server, not the CLIENT

The same situation, but for GraphQL…
Is there any elastic way to request dynamic zones via Graphql without explicitly defining each of them in a query?
For example, I DON’T want to do something like this:

query Homepage {
  components {
    ... on SliderComponent {
      image
      text
    }
    ... on ParagraphComponent {
      title
      description
    }
    // and so on...
  }
}

Instead, somehow, I’d like to be able to get all of the dynamic zones without querying them separately.
So ideally would be something like this:

query Homepage {
  components
}

and that would return all of the possible dynamic zone components with their nested fields.

The best scenario is to query all the nested data within the dynamic zones using something like in RestApi http://localhost:1337/api/pages?populate[dynamiczones]

NOTE: I know that the queries above are not correct, but this is just an idea of the query shape.

Work for me

@urbandale @sg-code
Have you considered using this:

const collectionType = 'api::page.page';
      const allPages = await strapi.entityService.findMany(collectionType, {
        fields: ["*"],
        filters: { },
        sort: { },
        populate: {
          // content [is the name of the dynamic zone in page]
         // Note: in @urbandale's Example Content is uppercase.
          content: {
            populate: "*"
          },
        }
      });

Atleast you don’t have to manually add each new component in your dynamic-zone.

Hi guys,

I work on the new version of a magazine’s website and struggling a bit with deep population, especially in dynamic zones (articles that can contain text, images and quotes). I’ve never been able to make any of the above work, especially the “image” components in the dynamic zone were never populating. I tried to give a shot at the strapi-plugin-populate-deep - npm .

Magic! the image components are populating with captions, alternative texts, formats, etc… But there is one caveat with this plugin: An article needs to display its author, which was super easy with Strapi 3, but that I now need to extract from the strapi.entityService and reinject in the sanitized entity manually in v4 like this:

const sanitizedEntity = await this.sanitizeOutput(info, ctx);
    sanitizedEntity[0].createdBy = {
      id: info[0].createdBy.id,
      firstname: info[0].createdBy.firstname,
      lastname: info[0].createdBy.lastname
    }

Here’s what I get when I use the query: ?populate=*

{
    "data": [
        {
            "id": 1,
            "attributes": {
                "title": "Quinzième Album ",
                "slug": "caravan-quinzieme-album",
                "isOnFrontPage": false,
                "createdAt": "2021-10-15T18:05:37.571Z",
                "updatedAt": "2022-07-31T17:22:21.249Z",
                "publishedAt": "2021-10-15T18:15:22.487Z",
                "artistName": "Caravan",
                "image": {
                    "data": {
                        "id": 15,
                        "attributes": {
                            "name": "It's None Of Your Business Album Cover.jpeg",
                            "alternativeText": "Caravan Cover Image",
                            "caption": "It's None Of Your Business by Caravan",
                            "width": 1200,
                            "height": 1200,
                            "formats": {
                                "large": {
                                    "ext": ".jpeg",
                                    "url": "https://res.cloudinary.com/bigbangmag/image/upload/v1656698521/v2images/large_It_s_None_Of_Your_Business_Album_Cover_4cbe83397c.jpg",
                                    "hash": "large_It_s_None_Of_Your_Business_Album_Cover_4cbe83397c",
                                    "mime": "image/jpeg",
                                    "name": "large_It's None Of Your Business Album Cover.jpeg",
                                    "path": null,
                                    "size": 222.33,
                                    "width": 1000,
                                    "height": 1000,
                                    "provider_metadata": {
                                        "public_id": "v2images/large_It_s_None_Of_Your_Business_Album_Cover_4cbe83397c",
                                        "resource_type": "image"
                                    }
                                },
                                "small": {
                                    "ext": ".jpeg",
                                    "url": "https://res.cloudinary.com/bigbangmag/image/upload/v1656698523/v2images/small_It_s_None_Of_Your_Business_Album_Cover_4cbe83397c.jpg",
                                    "hash": "small_It_s_None_Of_Your_Business_Album_Cover_4cbe83397c",
                                    "mime": "image/jpeg",
                                    "name": "small_It's None Of Your Business Album Cover.jpeg",
                                    "path": null,
                                    "size": 67.28,
                                    "width": 500,
                                    "height": 500,
                                    "provider_metadata": {
                                        "public_id": "v2images/small_It_s_None_Of_Your_Business_Album_Cover_4cbe83397c",
                                        "resource_type": "image"
                                    }
                                },
                                "medium": {
                                    "ext": ".jpeg",
                                    "url": "https://res.cloudinary.com/bigbangmag/image/upload/v1656698522/v2images/medium_It_s_None_Of_Your_Business_Album_Cover_4cbe83397c.jpg",
                                    "hash": "medium_It_s_None_Of_Your_Business_Album_Cover_4cbe83397c",
                                    "mime": "image/jpeg",
                                    "name": "medium_It's None Of Your Business Album Cover.jpeg",
                                    "path": null,
                                    "size": 135.74,
                                    "width": 750,
                                    "height": 750,
                                    "provider_metadata": {
                                        "public_id": "v2images/medium_It_s_None_Of_Your_Business_Album_Cover_4cbe83397c",
                                        "resource_type": "image"
                                    }
                                },
                                "thumbnail": {
                                    "ext": ".jpeg",
                                    "url": "https://res.cloudinary.com/bigbangmag/image/upload/v1656698520/v2images/thumbnail_It_s_None_Of_Your_Business_Album_Cover_4cbe83397c.jpg",
                                    "hash": "thumbnail_It_s_None_Of_Your_Business_Album_Cover_4cbe83397c",
                                    "mime": "image/jpeg",
                                    "name": "thumbnail_It's None Of Your Business Album Cover.jpeg",
                                    "path": null,
                                    "size": 9.98,
                                    "width": 156,
                                    "height": 156,
                                    "provider_metadata": {
                                        "public_id": "v2images/thumbnail_It_s_None_Of_Your_Business_Album_Cover_4cbe83397c",
                                        "resource_type": "image"
                                    }
                                }
                            },
                            "hash": "It_s_None_Of_Your_Business_Album_Cover_4cbe83397c",
                            "ext": ".jpeg",
                            "mime": "image/jpeg",
                            "size": 308.79,
                            "url": "https://res.cloudinary.com/bigbangmag/image/upload/v1656698519/v2images/It_s_None_Of_Your_Business_Album_Cover_4cbe83397c.jpg",
                            "previewUrl": null,
                            "provider": "cloudinary",
                            "provider_metadata": {
                                "public_id": "v2images/It_s_None_Of_Your_Business_Album_Cover_4cbe83397c",
                                "resource_type": "image"
                            },
                            "createdAt": "2022-07-01T18:02:04.135Z",
                            "updatedAt": "2022-07-01T18:02:04.135Z"
                        }
                    }
                },
                "content": [
                    {
                        "id": 1,
                        "__component": "paragraph.paragraph",
                        "paragraph": "Caravan vient de sortir son quinzième album \"It's None Of Your Business\" le 08 octobre sur le label Madfish. Il est composé de 10 titres pour une durée totale de cinquante minutes."
                    },
                    {
                        "id": 1,
                        "__component": "image.image"
                    },
                    {
                        "id": 2,
                        "__component": "paragraph.paragraph",
                        "paragraph": "1. Down From London (4:03) \n2. Wishing You Were Here (3:55) \n3. It’s None Of Your Business (9:40) \n4. Ready Or Not (4:45) \n5. Spare A Thought (4:06) \n6. Every Precious Little Thing (4:25) \n7. If I Was To Fly (3:23) \n8. I’ll Reach Out For You (8:07) \n9. There Is You (4:26) \n10. Luna’s Tuna (3:14) "
                    },
                    {
                        "id": 2,
                        "__component": "image.image"
                    },
                    {
                        "id": 1,
                        "__component": "quote.quote",
                        "quote": "Assis en cercle avec un contact visuel dans une grande salle était nécessaire. Je préfère de loin cette méthode parce que vous pouvez échanger des idées les unes avec les autres au fur et à mesure qu'elles se produisent et exprimer des encouragements lorsque tout commence à s'enclencher. Il est beaucoup plus gratifiant de pouvoir se lancer des insultes en personne plutôt que par téléphone ou par e-mail. C'est quelque chose dans lequel nous sommes tous très expérimentés, croyez-moi !",
                        "quoteAuthor": "Pye Hastings"
                    }
                ],
                "artists": {
                    "data": [
                        {
                            "id": 2,
                            "attributes": {
                                "name": "Caravan",
                                "slug": "caravan-royaume-uni",
                                "country": "Royaume-Uni",
                                "createdAt": "2022-07-01T18:09:26.154Z",
                                "updatedAt": "2022-07-01T18:09:27.544Z",
                                "publishedAt": "2022-07-01T18:09:27.541Z"
                            }
                        }
                    ]
                },
                "createdBy": {
                    "data": {
                        "id": 1,
                        "attributes": {
                            "firstname": "Thierry",
                            "lastname": "Di Lenarda"
                        }
                    }
                }
            }
        }
    ],
    "meta": {}
}

So all good, except the “image.image” components.

When using the query ?populate=deep,6, I get a 500 Error and points to my createdBy lines above (“Cannot read properties of undefined (reading ‘id’)”)
So it seems that the plugins gets rid of everything from the “admin::user” plugin because when I log the response right after strapi.entityService, createdBy, updatedBy, publishedBy are all completely gone.
On the other hand, my image components are populated completely.

{
                        "id": 2,
                        "__component": "image.image",
                        "image": {
                            "data": {
                                "id": 16,
                                "attributes": {
                                    "name": "Pye Hastings.jpeg",
                                    "alternativeText": "Pye Hastings Image",
                                    "caption": "Pye Hastings de Caravan",
                                    "width": 1280,
                                    "height": 1706,
                                    "formats": {
                                        "large": {
                                            "ext": ".jpeg",
                                            "url": "https://res.cloudinary.com/bigbangmag/image/upload/v1656698667/v2images/large_Pye_Hastings_0b7d524201.jpg",
                                            "hash": "large_Pye_Hastings_0b7d524201",
                                            "mime": "image/jpeg",
                                            "name": "large_Pye Hastings.jpeg",
                                            "path": null,
                                            "size": 65.46,
                                            "width": 750,
                                            "height": 1000,
                                            "provider_metadata": {
                                                "public_id": "v2images/large_Pye_Hastings_0b7d524201",
                                                "resource_type": "image"
                                            }
                                        },
                                        "small": {
                                            "ext": ".jpeg",
                                            "url": "https://res.cloudinary.com/bigbangmag/image/upload/v1656698668/v2images/small_Pye_Hastings_0b7d524201.jpg",
                                            "hash": "small_Pye_Hastings_0b7d524201",
                                            "mime": "image/jpeg",
                                            "name": "small_Pye Hastings.jpeg",
                                            "path": null,
                                            "size": 18.46,
                                            "width": 375,
                                            "height": 500,
                                            "provider_metadata": {
                                                "public_id": "v2images/small_Pye_Hastings_0b7d524201",
                                                "resource_type": "image"
                                            }
                                        },
                                        "medium": {
                                            "ext": ".jpeg",
                                            "url": "https://res.cloudinary.com/bigbangmag/image/upload/v1656698668/v2images/medium_Pye_Hastings_0b7d524201.jpg",
                                            "hash": "medium_Pye_Hastings_0b7d524201",
                                            "mime": "image/jpeg",
                                            "name": "medium_Pye Hastings.jpeg",
                                            "path": null,
                                            "size": 37.99,
                                            "width": 563,
                                            "height": 750,
                                            "provider_metadata": {
                                                "public_id": "v2images/medium_Pye_Hastings_0b7d524201",
                                                "resource_type": "image"
                                            }
                                        },
                                        "thumbnail": {
                                            "ext": ".jpeg",
                                            "url": "https://res.cloudinary.com/bigbangmag/image/upload/v1656698665/v2images/thumbnail_Pye_Hastings_0b7d524201.jpg",
                                            "hash": "thumbnail_Pye_Hastings_0b7d524201",
                                            "mime": "image/jpeg",
                                            "name": "thumbnail_Pye Hastings.jpeg",
                                            "path": null,
                                            "size": 3.04,
                                            "width": 117,
                                            "height": 156,
                                            "provider_metadata": {
                                                "public_id": "v2images/thumbnail_Pye_Hastings_0b7d524201",
                                                "resource_type": "image"
                                            }
                                        }
                                    },
                                    "hash": "Pye_Hastings_0b7d524201",
                                    "ext": ".jpeg",
                                    "mime": "image/jpeg",
                                    "size": 181.54,
                                    "url": "https://res.cloudinary.com/bigbangmag/image/upload/v1656698665/v2images/Pye_Hastings_0b7d524201.jpg",
                                    "previewUrl": null,
                                    "provider": "cloudinary",
                                    "provider_metadata": {
                                        "public_id": "v2images/Pye_Hastings_0b7d524201",
                                        "resource_type": "image"
                                    },
                                    "createdAt": "2022-07-01T18:04:29.349Z",
                                    "updatedAt": "2022-07-01T18:04:29.349Z"
                                }
                            }
                        }
                    },

Has anyone any idea how to make this work? Strapi 4 is really NOT making our life easier and I find the documentation so light and incomplete. I understand their choice of letting the developers decide when and what to populate, that’s fine. But then they should provide a comprehensive way or mechanism to activate population or not, this is bad DX. I’ve been turning my head upside down on this problem for 3 weeks which is ridiculous. As light and as the so-called migration guides Mongo → mySQL, which has not worked as well despite 3 attempts.

Well done, this work means an article/tutorial I would like to read.

1 Like