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.

Show field from related collection

default discord avatar
dland84505 months ago
5

I am using payload with postgres and I have two collections that are related,

Users

and

RelatedUserInfo

. They are related together by the

externalId

and

userExternId

fields (which is not the primary key on either collection).



export const Users: CollectionConfig = {
    slug: 'users',
    fields: [
        {
            name: 'externalId',
            type: 'text'
        },
        {
            name: 'firstName',
            type: 'text',
            required: true
        }
    ]
}

export const RelatedUserInfo: CollectionConfig = {
    slug: 'related-user-info',
    fields: [
        {
            name: 'userExternId',
            type: 'text'
        },
        {
            name: 'email',
            type: 'text',
            required: true
        }
    ]
}

I want the admin console for

RelatedUserInfo

to show the

email

field from the corresponding

User

but I'm not sure how to do this. All the field types that I would think would do this

relationship

or

join

or

virtual

seem to require that the two tables are related to each other by the parent's primary key, but this is not the case with my tables. I need some way to tell it to create a relationship between

Users.externalId

and

RelatedUserInfo.userExternId

.

  • default discord avatar
    rubixvi5 months ago

    Didnt read the docs? You use relationship field.

  • default discord avatar
    dland84505 months ago

    I think maybe I'm not explaining my goal very well. I don't want the payload user to have to select a

    User

    value within the

    RelatedUserInfo

    collection via a dropdown list or something like that. The data in both of these collections is not managed by the user. It's entered via the api and it's constantly changing. I want payload to basically join the two tables together and show the email of the corresponding

    User

    record (assuming one exists) within the

    RelatedUserInfo

    record . In order to do that I need a way to tell payload that those two collections are related via the

    Users.ExternalId

    and

    RelatedUserInfo.UserExternId

    fields. That's what I'm not sure how to do.

  • default discord avatar
    rubixvi5 months ago

    using hooks combined with relationship will solve that

  • default discord avatar
    puzzleno0395 months ago

    Are you trying to display

    email

    on the User info?


    You could build a custom field for

    externalID

    that will query based on the value.


    {
      name: 'userExternalId',
      type: 'text',
      required: false,
      admin: {
        allowEdit: false,
        components: {
           Field: "@/components/RelatedInfo" // the custom component
        },
      },
    }

    Here's the custom component might looks like :


    export default function RelatedInfo() {
      const {value, setValue} = useField<string | undefined>() // value of userExternalId field earlier
      
      // states
      const [relatedUser, setRelatedUser] = useState<User | null>(null)
      const [loadingUser, setLoadingUser] = useState(false)
    
      useEffect(() => {
    
        setLoadingUser(true)
        getUser(value)
          .then(setRelatedUser)
          .catch(console.error)
          .finally(() => setLoadingUser(false))
      }, [value])
    
      const getUser = async (userExternalId: string): Promise<User | null> => {
      // we query user collection 
        const res = await fetch(
          `/api/users?where[userExternalId][equals]=${encodeURIComponent(email)}`,
          { headers: { 'Content-Type': 'application/json' } }
        )
    
        const json = await res.json()
        return json.docs?.[0] ?? null
      }
    
      if (value) {
        return (
          <>
              {loadingUser && <p>Loading user…</p>}
              {relatedUser && (
                <h1>{relatedUser.email}</h1>
              )}
          </>
        )
      }
    }

    I'd say this one prob fit ur case better, and custom field allows you do much much more.




    Or, have a duplicate of the

    email

    on your

    RelatedUser

    collection. Then you had a hook every

    email

    change to update the data on

    RelatedUser

    collection based on

    externalId

    or something .


    Although this meant that there will be duplicate data and you might not want that.



    You can see more on querying [here](

    https://payloadcms.com/docs/queries/overview#writing-queries

    ) and building custom field [here](

    https://payloadcms.com/docs/custom-components/overview#building-custom-component

    )

  • default discord avatar
    dland84504 months ago

    Okay, interesting solution, thank you for putting that together.



    Okay, I ended up solving by using a virtual field with a hook to query for the data I wanted from the other table. I added this to the

    RelatedUserInfo

    table:


    {
        name: 'userExternId',
        type: 'text'
    },
    {
        name: 'userEmail',
        type: 'text',
        virtual: true,
        hooks: {
            afterRead: [
                async ({ siblingData }) => {
                    const payload = await getPayload({ config });
    
                    const res = await payload.find({
                        collection: 'users',
                        select: { email: true },
                        where: { externalId: { equals: siblingData.userExternId }}
                    });
                    
                    if (res.docs.length === 1) {
                        return res.docs[0].email;
                    }
                }
            ]
        }
    }
Star on GitHub

Star

Chat on Discord

Discord

online

Can't find what you're looking for?

Get dedicated engineering support directly from the Payload team.