Strapi V4 populate Media and Dynamiczones from Components

We had the same problem with deeply nested components in dynamiczones. After a bit of fiddling, this is what we came up with.

Created a new file src/helpers/populate.js

const { createCoreController } = require("@strapi/strapi/lib/factories");

function populateAttribute({ components }) {
  if (components) {
    const populate = components.reduce((currentValue, current) => {
      return { ...currentValue, [current.split(".").pop()]: { 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 currentValue;
    }
    return {
      ...currentValue,
      [current]: populateAttribute(attribute),
    };
  }, {});
};

function createPopulatedController(uid, schema) {
  return createCoreController(uid, () => {
    console.log(schema.collectionName, getPopulateFromSchema(schema));
    return {
      async find(ctx) {
        ctx.query = {
          ...ctx.query,
          populate: getPopulateFromSchema(schema),
        };
        return await super.find(ctx);
      },
      async findOne(ctx) {
        ctx.query = {
          ...ctx.query,
          populate: getPopulateFromSchema(schema),
        };
        return await super.findOne(ctx);
      },
    };
  });
}

module.exports = createPopulatedController;

then in controllers needing to be deeply populated:

"use strict";

/**
 *  homepage controller
 */

const schema = require("../content-types/homepage/schema.json");
const createPopulatedController = require("../../../helpers/populate");

module.exports = createPopulatedController("api::homepage.homepage", schema);

What it basically does, is overriding the default controller by dynamically creating a “populate” query from the content type schema. I hope it might help someone…

6 Likes