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.

How can I retrieve the current collection name within the filter options of the relationship field?

default discord avatar
mng93912 years ago
16

Is there any way I can fetch the current collection name within the filter options?

  • discord user avatar
    jarrod_not_jared
    2 years ago

    you should have access to

    relationTo

    I believe



    which would be the slug of the collection

  • default discord avatar
    mng93912 years ago
    @281120856527077378

    According to the documentation, the "relationTo" parameter is used to filter based on the defined field relation, indicating that it is unrelated to the slug of the collection.

  • discord user avatar
    jarrod_not_jared
    2 years ago

    What are ya looking to do exactly?

  • default discord avatar
    mng93912 years ago

    something like that


    filter: ({ data, id }) => { if (!id) { return { id: { exists: false } }; } const currentCollection = ... return { [

    ${currentCollection}.reference

    ]: { equals: id } }; },
  • discord user avatar
    jarrod_not_jared
    2 years ago

    You want to know the collection that the relationship field was defined in, like the parent config collection?

  • default discord avatar
    mng93912 years ago

    No, for example, if we have a URL like "

    http://localhost:3000/cms/admin/collections/blogs/id

    ", the currentCollection in this case should be "blogs"

  • default discord avatar
    ssyberg2 years ago

    This is related to this feature request:

    https://github.com/payloadcms/payload/discussions/2829
  • discord user avatar
    jmikrut
    2 years ago

    ohhh I see the issue here



    is it that you want to

    re-use

    a single

    filterOptions

    function across many different fields, but you need to know which collection the parent field is contained on?



    because if i understand correctly, you let's say you have a blogs collection, and then there's some relationship field within the blogs collection. And you want to build a

    filterOptions

    function for that field, but that same function is also used on other collections



    so you need to know if the

    filterOptions

    field is used on

    blogs

    or a different collection



    if this is the case, the pattern that we typically suggest is to create a higher-order function, where you can pass in the collection name, along with any other data that you need, and then return a

    filterOptions

    function



    so it would be like this:



    type GetFilterOptionsArgs = {
      collection: string
    }
    
    const getFilterOptions = (args: GetFilterOptionsArgs): FilterOptions => {
      const { collection } = args;
    
      // Return a typical filterOptions func here, but you now have access
      // to the parent collection that it's used on
      return ({ relationTo, siblingData }) => {
        if (relationTo === "products") {
          return {
            stock: { greater_than: siblingData.quantity },
          };
        }
      
        if (relationTo === "services") {
          return {
            isAvailable: { equals: true },
          };
        }
      },
    }
    
    
    const myRelationshipField: Field = {
      type: 'relationship',
      name: 'myRelationshipField',
      relationTo: ['products', 'services'],
      // Call your higher-order function, passing in the collection slug
      filterOptions: getFilterOptions({ collection: 'my-parent-collection' }),
    }
  • default discord avatar
    ssyberg2 years ago
    if this is the case, the pattern that we typically suggest is to create a higher-order function, where you can pass in the collection name,

    Yea we do this all over the place and it smells a bit funny to me - we have on order of 50 reusable "components" now and we're passing this info along in each of them. It's honestly a bit error prone and in some scenarios we need to pass these down multiple levels of nested fields/blocks and it's hard to track. IMO "data" knowing what data it actually represents it a pretty common pattern, Graphql does this natively with

    __typename

    It also feel a bit not DRY / redundant to have this setup all over the place:



    const Posts = {
        slug: 'posts',
        fields: [
            Hero({collection: 'posts'})
  • default discord avatar
    mng93912 years ago

    Additionally, in cases where a block contains a relationship field and is utilized across different collections, I believe we might encounter the same issue

  • discord user avatar
    jmikrut
    2 years ago
    @778799229988110337

    i like the concept of exposing a collection in a variety of places, and i think we can build this at some point. there will be a lot to think through there though



    there are a LOT of places that we will need to utilize this new feature

  • default discord avatar
    ssyberg2 years ago

    Word, I did a little proof of concept and a single line change made this available in all relationships but I already can tell it'll be much more in depth

  • discord user avatar
    jmikrut
    2 years ago

    filterOptions is one spot, but also - - validations, hooks, custom components, access control, defaultValue, probably more



    and i'd like to identify a common pattern



    like....

  • default discord avatar
    ssyberg2 years ago

    I added it in the data loader and that seemed promising, but I could see that it wasn't flowing through everywhere I wanted it

  • discord user avatar
    jmikrut
    2 years ago

    because sometimes it might be a collection, but sometimes it might be a global - and then sometimes you might be on a version



    so it might need to be something like

    context: { collectionSlug, globalSlug, isVersion, payloadAPI }

    and likely more



    the pattern i suggested should still work here

  • default discord avatar
    ssyberg2 years ago

    this was my first attempt at touching core code so I'm sure this is a silly approach:


            result.docs.forEach((doc) => {
              const docKey = JSON.stringify([
                collection,
                doc.id,
                depth,
                currentDepth,
                locale,
                fallbackLocale,
                overrideAccess,
                showHiddenFields,
              ]);
              const docsIndex = keys.findIndex((key) => key === docKey);
    
              doc._collection = collection;
    
              if (docsIndex > -1) {
                docs[docsIndex] = doc;
              }
            });


    but yea I hear ya!



    for the moment we're adding a beforeChange hook to all collections - we've already implemented an inheritance system so this is just a few lines in our "base collection"

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.