gatsby-uc / gatsby-source-strapi

Gatsby source plugin for building websites using Strapi as a data source
MIT License
355 stars 183 forks source link

Cannot source relational field in component #323

Closed davidalexoliveira closed 1 year ago

davidalexoliveira commented 2 years ago

Cannot by any means get my relational field data to show up in GraphQL. Tried multiple config structures but nothing works. I can source a title that is in the component, but not the relational field. The strapi graphql sources the data fine, but not the Gatsby gql

Could someone help and point me in that right direction? Should I avoid the plugin and create my nodes through REST instead?

    {
      resolve: `gatsby-source-strapi`,
      options: {
        apiURL: "http://localhost:1337",
        accessToken:
          "***",
        collectionTypes: [
          {
            singularName: "page",
            queryParams: {
              populate: "*",
              sections: {
                populate: "*",
                test: { //component
                  populate: "*",
                  features: { //relational field
                    populate: "*",
                  },
                },
              },
            },
          },
        ],
      },
    }
image
leasytime commented 2 years ago

Please double check your populate structure. Working example below:

          {
            singularName: "service",
            queryParams: {
              publicationState: process.env.GATSBY_IS_PREVIEW === "true" ? "preview" : "live",
              populate: {
                seoBasic: '*',
                features: {
                  populate: {
                    feature_item: {
                      populate: {
                        feature_item_image: '*'
                      }
                    },
                  }, 
                },                
                hero: {
                  populate: {
                    hero_image: '*'
                  },
                },
                faqs: {
                  populate: {
                    faq_item: '*',
                  },
                },
                cta: '*',
                all_features: '*',
              },
            },
          },
davidalexoliveira commented 2 years ago

Thanks for your help. I've adapted your populate structure below, but didn't work. And it sourced less data (now my sections dynamic zone doesn't show up). Below is the code and an image of my actual content page. I can access the individual title field inside the component, but not the relations.

{
      resolve: `gatsby-source-strapi`,
      options: {
        apiURL: "http://localhost:1337",
        accessToken:
          "***",
        collectionTypes: [
          {
            singularName: "page",
            queryParams: {
              populate: "*",
              populate: {
                sections: { // dynamic zone name
                  populate: {
                    test: { // component name
                      populate: {
                        features: "*", // relational field
                        feature: "*", // relational field, don't know if singluar will help
                      },
                    },
                  },
                },
              },
            },
          },
        ],
      },
    },
image
youmeokay commented 2 years ago

I got a similar setup going with deep-populating this specific section, not via gatsby-conf, because I think the "problem" here is that strapi won't populate on that level. So whatever you do in gatsby conf, won't affect it.

I think you gotta add a helper in your strapi setting, to query these sections and it's content.

add a population helper in strapi:

./src/helpers/populate.js

then go modify your page controller (in your case: page::page)

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


"use strict";

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

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

add this to your populate helper and change the specific section where it points out what to populate (in my case the dynamic zone is called "modules".

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),
      modules: {
        populate: {
          media: "*", 
          cover: "*", l
          inks: "*", 
          file: "*", 
          carouselentry: "*", 
          galerie: {
            populate: {
                media: "*"
            }
          },
          articles: {
            populate:  "*"
          },
          horizontalentry: {
            populate:  "*"
          },
          carouselentry: {
            populate: {
                media: "*"
            }
          },
        }
      },
    };
  }, {});
};

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;

Not sure how good this is for overall performance, but in my case it works smooth and as expected. Got all the 4th level fields and carousel images and what not. Hope that helps!

Here is the relevant part of my gatsby conf;

{
      singularName: "about",
      queryParams: {
        publicationState: process.env.GATSBY_IS_PREVIEW === "true" ? "preview" : "live",
        populate: {
          modules: {
            populate: "*",
          },
        },
      },
    },
moonmeister commented 1 year ago

Thanks for your interest in this project. This plugin is moving into the Gatsby User Collective and this repo will be archived. Please open an issue in that repository, submit a PR if you'd like to see this implemented, or join us on Discord if you have questions!