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.

AfterChangeHook Not Running After DB Insertion

default discord avatar
zed0547last year
21

Hey

@131537558453747712



Yeah, this is a good use case for an afterChange or a beforeChange collection hook.

afterChange

should run after the data has been saved

  • default discord avatar
    intelligentlylast year

    For some reason it's complaining that the document does not yet exist.



    Note that

    document

    and

    document-chunk

    are two different collections



    import { Document } from '@/payload-types'
    import type { CollectionAfterChangeHook, CollectionConfig } from 'payload'
    
    const afterChangeHook: CollectionAfterChangeHook<Document> = async ({ doc, req }) => {
      await req.payload.create({
        collection: 'document-chunk',
        data: {
          chunk: 'chunk2',
          embedding: '[1,2,3,4,5,6,7,8,8,8]',
          document: doc.id, // This complains that there's no document with this ID yet
        },
        req,
      })
    
      console.log('About to fetch chunks')
    
      await req.payload.find({
        collection: 'document-chunk',
        where: {
          document: {
            equals: doc.id,
          },
        },
        req,
      })
    }
    
    export const Documents: CollectionConfig = {
      slug: 'documents',
      upload: {
        staticDir: 'documents',
        adminThumbnail: 'thumbnail',
        mimeTypes: ['application/pdf'],
      },
      fields: [
        {
          name: 'alt',
          type: 'text',
        },
      ],
    
      hooks: {
        afterChange: [afterChangeHook],
      },
    }
  • default discord avatar
    zed0547last year

    Can you try scoping it to the 'create' operation, there should definitely be an id there. Also your second req.payload.find operation there is redundant as the create operation will return the created document



    document-chunk

    has a relationship field set to

    documents

    with a field name of

    document

    , correct?

  • default discord avatar
    rilromlast year

    I've had this happen before if I have any other hooks that are involved with the above collections (both collection-level and field-level) that don't have a

    req

    assigned to them.



    Most recently it was a

    beforeValidate

    hook without a

    req

    that caused a very similar issue for me, make sure to check there.

  • default discord avatar
    intelligentlylast year

    Yes

  • default discord avatar
    zed0547last year

    Selectively including/excluding

    req

    can create all sorts of nonsense

  • default discord avatar
    intelligentlylast year

    This is a completely new project

  • default discord avatar
    zed0547last year

    What are the odds that your issues go away if you remove the

    req

    from the

    find
  • default discord avatar
    rilromlast year

    I learnt that the hard way 😂

  • default discord avatar
    zed0547last year

    Oh man, I've been trying to find the root of this issue since beta - something

    real

    weird happens. I have a PR for

    plugin-search

    from October that shows this



    What are the odds that your issues go away if you remove the req from the find

    Which is why I ponder the above



    https://github.com/payloadcms/payload/pull/9623
  • default discord avatar
    intelligentlylast year

    Yeah that straight up worked. Not sure what exactly I changed, cause initially I didn't pass

    req

    on either

  • default discord avatar
    zed0547last year

    Bingo



    I've seen so many of these I actually have notes in my notebook on different scenarios. I have theories but nothing conclusive and have inspected the transaction code pretty intensely and am still not too sure. My leading theory is that if you follow the transaction, from the POV of that transaction that document has not been "comitted" or "created" yet so it fails to find it within the transaction itself.

  • default discord avatar
    intelligentlylast year

    If I remove the req from the create, it also breaks

  • default discord avatar
    zed0547last year

    The create necessarily needs that req



    It must be there



    But subsequent finds will fail if you include the req there. I can tell in advance that you're on Postgres by the way you describe how the calls fail

  • default discord avatar
    intelligentlylast year

    Interesting. So conceptually, by including

    req

    in the create, we simply add the creation to the transaction

  • default discord avatar
    zed0547last year

    Correct



    But if you do a

    find

    right after (with a

    req

    ), it will fail to find the doc

  • default discord avatar
    intelligentlylast year

    Hold up, but I still don't get why that

    would necessarily

    be required



    Like why would it be required on the

    create
  • default discord avatar
    zed0547last year

    Because everything up to that point is operating within a transaction

    https://payloadcms.com/docs/database/transactions#async-hooks-with-transactions

    To be clear - you

    don't

    have to use a req but it is highly encouraged especially if you have other hooks or operations



    In this particular case, a create with a req followed by a find with a req does something weird and fails, as you've observed

  • default discord avatar
    intelligentlylast year

    Well in this particular case, a create

    without

    a req followed by a find

    without

    a req also does something weird and fails



    ^ This is the scenario which confuses me



    It's for sure just my own lack of knowledge of how Payload works. I'll do some more research to understand this better

  • default discord avatar
    zed0547last year

    Because that create is assuming that a doc.id exists but what I

    think

    is happening is that the transaction, while saving the data, is not necessarily comitted yet



    You can assume that the afterChange runs after the data is saved, but that transaction may not have been comitted yet if that makes sense

  • default discord avatar
    intelligentlylast year

    I need a deeper understanding of postgres to understand the difference between comitted transactions and data being saved 😅

  • default discord avatar
    zed0547last year

    Don't sweat it too much, just try to pass

    req

    where possible and be mindful of this caveat here. I like to think of transactions as isolated "paths" where there's a path outside the transaction, and inside the transaction. Read through the link I sent above too, ti should make things a bit more clear.



    Otherwise I'll go ahead and mark this as solved if things started working for ya here!

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.