2 levels of relationship field

default discord avatar
agolovan
2 months ago
17

I did the following experiment: created collection with one field - text field and set this field as title. I created another collection with one field - relationship - and linked to first collection. I added some data and saw field values to select. I set a title as this field for this collection. I created 3rd collection and added one field - relationship - and linked to collection 2. When I started adding data, I saw just payload IDs in place of field values. This is what are users are complaining about. They want to see field values not IDs. Is that by design or we could do some trick to fix that.

  • default discord avatar
    .bakry
    2 months ago

    If i got you right i think depth is your answer



    https://payloadcms.com/docs/getting-started/concepts#depth
  • default discord avatar
    agolovan
    2 months ago

    We are not running any queries at this point - we just use Payload CMS UI to enter a data for collection that we created.

  • discord user avatar
    patrikkozak
    Payload Team
    2 months ago

    Hey @agolovan - if I understand correctly, you could use a virtual field to get specific data for your doc title.



    So in your case, you have 3 collections.


    -

    CollectionOne

    - w/ text field set as title


    -

    CollectionTwo

    - relationship to

    CollectionOne

    -

    CollectionThree

    - relationship to

    CollectionTwo

    In order for

    CollectionThree

    to see field values, in your

    CollectionTwo

    you'd create a virtual field that looks like this:



    {
          name: 'title',
          type: 'text',
          admin: {
            hidden: true
          },
          hooks: {
            beforeChange: [
              async ({ data }) => {
                const req = await fetch(`${process.env.URL}/api/collectionOne/${data.relationshipOne.value}`)
                  .then(res => res.json())
                  .then(data => {
                    return data.title
                  })
                return req
    
              }
            ]
          }
        },


    You would then set

    useAsTitle: 'title'

    relationshipOne

    in this case, is the name of the relationship field in this collection (CollectionTwo)



    Now that CollectionTwo should have titles, CollectionThree should be seeing those titles instead of IDs



    Let me know if this makes sense or if you need any help!

  • default discord avatar
    agolovan
    2 months ago

    Unfortunalty. it does not work. After looking at virtual-fields example, i got like that:


    const slugName = 'linkedField';



    const getTitleToUse: FieldHook = async (args) => {



    const {


    value,


    req,


    } = args;



    const linkedItem = await payload.find({


    collection: 'DefaultLocalizedText',


    locale: req.locale,


    where: {


    id: { equals: value },


    },


    });


    return linkedItem.docs[0].LocalizedText;


    };



    const LocalizedTextLinkedCollection1: CollectionConfig = {


    slug: slugName,


    admin: {


    useAsTitle: slugName,


    },


    access: {},


    fields: [


    {


    name: slugName,


    type: 'relationship',


    relationTo: 'DefaultLocalizedText',


    maxDepth: 0,


    hooks: {


    afterRead: [


    getTitleToUse,


    ],


    },


    },


    ],


    };



    However, I am getting the following server side error:



    As I understand for relationship field I am trying to display a string as a title, but it is looking for ObjectId.


    This is what I see at the screen:



    @patrikkozak Did anybody try doing something like that or this is just first attempt? 🙂



    Thanks again for your message!

    image.png
    image.png
    image.png
    image.png
  • discord user avatar
    patrikkozak
    Payload Team
    2 months ago

    @agolovan Yes, others are using this same method. Check this link out:

    https://payloadcms.com/community-help/discord/useastitle-a-field-not-id-from-a-relationship

    The example I provided for you is a working example, did you give that a shot?



    I will look into your example shortly and see what's going on

  • default discord avatar
    agolovan
    2 months ago

    This code is not related to relationship field, it is for text field:


    {


    name: 'title',


    type: 'text',


    admin: {


    hidden: true,


    },


    hooks: {


    beforeChange: [


    ({ data }) => {


    return data.course.title;


    }


    ],


    },


    }



    Or, this is just a virtual field that is not seen

  • discord user avatar
    patrikkozak
    Payload Team
    2 months ago

    Yes, this is the virtual field.



    The above

    text

    field simply acts as the

    title

    for your documents in your 2nd collection (w/ relationship field) - that way when your 3rd collection is a relationship to

    collectionTwo

    , you won't just see IDs

  • default discord avatar
    agolovan
    2 months ago

    wow - this is what I missed - let me try, thank you very much for your help!

  • discord user avatar
    patrikkozak
    Payload Team
    2 months ago

    No problem! I'm here if you have any other questions!

  • default discord avatar
    agolovan
    2 months ago

    @patrikkozak Thanks again for all your help - but I am having really weird problem when I am trying from CollectionThree select value from CollectionTwo:


    I see the following crash



    Did you guys saw anything like that?

    image.png
    image.png
  • discord user avatar
    patrikkozak
    Payload Team
    2 months ago

    Can you show me what your collection configs look like?

  • default discord avatar
    agolovan
    2 months ago

    @patrikkozak I was able to repro with the following collections:


    import { CollectionConfig } from 'payload/types';



    const DomainCollection: CollectionConfig = {


    slug: 'domains',


    labels: {


    singular: 'domain',


    plural: 'domains',


    },


    admin: {


    useAsTitle: 'domain',


    },


    access: {},


    fields: [


    {


    name: 'domain',


    type: 'text',


    }


    ],


    };



    export default DomainCollection;



    import { CollectionConfig } from 'payload/types';



    const RegionCollection: CollectionConfig = {


    slug: 'regions',


    labels: {


    singular: 'region',


    plural: 'regions',


    },


    admin: {


    useAsTitle: 'region',


    },


    access: {},


    fields: [


    {


    name: 'region',


    type: 'text',


    }


    ],


    };



    export default RegionCollection;



    import { CollectionConfig } from 'payload/types';



    const DomainsregionsCollection: CollectionConfig = {


    slug: 'domainsregions',


    labels: {


    singular: 'domainsregions',


    plural: 'domainsregions',


    },


    admin: {


    useAsTitle: 'domainsregions',


    },


    access: {},


    fields: [


    {


    name: 'domainsregions',


    type: 'relationship',


    relationTo: ['domains', 'regions'],


    hasMany: true,


    }


    ],


    };



    export default DomainsregionsCollection;



    If I am removing asTitle from DomainsregionsCollection, it is not crashing

  • discord user avatar
    patrikkozak
    Payload Team
    2 months ago

    Hey @agolovan - I went ahead and updated your collections to get this working:



    import { CollectionConfig } from 'payload/types';
    
    const DomainCollection: CollectionConfig = {
      slug: 'domains',
      labels: {
        singular: 'domain',
        plural: 'domains',
      },
      admin: {
        useAsTitle: 'domain',
      },
      access: {
        read: () => true,
        update: () => true,
        create: () => true,
      },
      fields: [
        {
          name: 'domain',
          type: 'text',
        },
      ],
    }
    
    export default DomainCollection;


    import { CollectionConfig } from 'payload/types';
    
    const RegionCollection: CollectionConfig = {
      slug: 'regions',
      labels: {
        singular: 'region',
        plural: 'regions',
      },
      admin: {
        useAsTitle: 'region',
      },
      access: {
        read: () => true,
        update: () => true,
        create: () => true,
      },
      fields: [
        {
          name: 'region',
          type: 'text',
          admin: {
            hidden: true
          },
          hooks: {
            beforeChange: [
              async ({ data }) => {
                const req = await fetch(`${process.env.URL}/api/domains/${data.relationshipOne.value}`)
                  .then(res => res.json())
                  .then(data => {
                    return data.domain
                  })
                return req
    
              }
            ]
          }
        },
        {
          name: 'relationshipOne',
          type: 'relationship',
          relationTo: ['domains'],
          access: {
            read: () => true,
            update: () => true,
            create: () => true,
          }
        },
      ],
    }
    
    export default RegionCollection;


    import { CollectionConfig } from 'payload/types';
    
    const DomainregionsCollection: CollectionConfig = {
      slug: 'domainregions',
      fields: [
        {
          name: 'RelationshipTwo',
          type: 'relationship',
          relationTo: ['regions'],
          maxDepth: 2,
        },
      ],
    }
    
    export default DomainregionsCollection;


    Couple things to note:


    -

    DomainCollection

    didn't require any changes



    -

    RegionCollection

    - This has a relationship field with a relationTo

    domains

    , I also added the virtual field here called

    region

    , it has a

    beforeChange

    hook that fetches the

    title

    of the domains doc you are doing a relation to. This way, the title of this document becomes the title of the

    DomainsCollection

    document we have a relationship with.



    -

    DomainregiosnCollection

    - this simply has a

    relationship

    field to the

    regions

    collection. Now when you look at values in this collection, you will see titles instead of IDs



    Let me know if this makes sense or need any further explanation.

  • default discord avatar
    agolovan
    2 months ago

    Yes and if you set admin: {


    useAsTitle: ''RelationshipTwo",


    }, for DomainregionsCollection, it has client side crash . Everything else is working, we did it a little different for virtual field, but this is not about that.



    If you put like that relationTo: 'regions', it is not crashing



    When I put for you those 3 collections, I made that very simple to be able to just to run locally and see a client side crash

  • discord user avatar
    patrikkozak
    Payload Team
    2 months ago

    Setting

    useAsTitle

    to

    RelationshipTwo

    will cause a crash because a relationship field returns an object of data, not a value.



    useAsTitle

    needs to be a value.



    So in order for the above to work, you'd need to create another virtual field in the

    DomainregionsCollection

    , similar to what you are doing in the

    RegionCollection
  • default discord avatar
    agolovan
    2 months ago

    Or just use like that: relationTo: 'regions'



    It works 😉



    Thank you very much!

  • discord user avatar
    patrikkozak
    Payload Team
    2 months ago

    No problem

Open the post
Continue the discussion in Discord
Like what we're doing?
Star us on GitHub!

Star

Connect with the Payload Community on Discord

Discord

online

Can't find what you're looking for?

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