Simplify your stack and build anything. Or everything.
Build tomorrow’s web with a modern solution you truly own.
Code-based nature means you can build on top of it to power anything.
It’s time to take back your content infrastructure.

Return of afterRead hook for relationship field

default discord avatar
thebergamo2 years ago
1 1

Hi there :)

Here I'm with another question...

What is the expected return in the afterRead hook?

Not sure if my configuration is wrong or something, but I created a field inside a block that based on some other field this should be populated in the API call.

This is my example:

import payload from "payload";
import { Block, FieldHook } from "payload/types";
import { Type as MediaType } from "../../collections/Media";
import { Type as TagType } from "../../collections/Tags";

export type Type = {
  blockType: "media";
  blockName?: string;
  media: MediaType[];
  tag: TagType[];
};

const afterReadHook: FieldHook<any, string[], any> = async (
  args
): Promise<string[]> => {
  const { value, siblingData, data, req } = args;

  if (req.user?.collection === "users") {
    return value;
  }

  console.log({ siblingData, value });
  const media = await payload.find({
    collection: "media",
    where: {
      tags: {
        in: siblingData.tag.join(","),
      },
    },
  });

  console.log({ media: media.docs });

  return media.docs.map(({ id }) => id);
};

export const MediaList: Block = {
  slug: "mediaList",
  labels: {
    singular: "Media List Block",
    plural: "Media List Blocks",
  },
  fields: [
    {
      name: "tag",
      label: "Tag",
      type: "relationship",
      relationTo: "tags",
      hasMany: true,
      required: true,
    },
    {
      name: "media",
      label: "Media",
      type: "relationship",
      relationTo: "media",
      hasMany: true,
      admin: {
        disabled: true,
      },
      hooks: {
        afterRead: [afterReadHook],
      },
    },
  ],
};

In this case, I would like to fetch all media with given tags specified in the field tag and return in the field media when this API is called.

As of now, it only works if in the return of afterRead hook I return an array of ids, but then it's not getting populated automatically.

Is it a valid use case for Payload or some of my code/configurations are wrong in this case?

  • Selected Answer
    discord user avatar
    jacobsfletch
    last year

    @thebergamo the afterRead hook should return a modified document. For reference, here's the types for that hook:

    and here are the related docs: https://payloadcms.com/docs/hooks/fields#field-hooks

    So your hook should look something like this (not tested):

    const afterReadHook: FieldHook<any, string[], any> = async (
      args
    ): Promise<string[]> => {
      const { doc, req } = args;
    
      if (req.user?.collection === "users") {
        return doc;
      }
    
      const media = await payload.find({
        collection: "media",
        where: {
          tags: {
            in: doc.tag.join(","),
          },
        },
      });
    
      return {
        ...doc,
        media: media.docs.map((doc) => doc.id),
      }
    };
Star on GitHub

Star

Chat on Discord

Discord

online

Can't find what you're looking for?

Get help straight from the Payload team with an Enterprise License.