Moralis.Cloud.beforeSave not triggered when adding tables through a sync job (plugin)

I ran into this a while back and it was doing my head in.

Could it be that a ‘Moralis.Cloud.beforeSave’ in Cloud Functions is not triggered when adding tables through a sync job (plugin)?

When I run the beforeSave just using the web3 UI it works.
When I delete all the tables and manually run the Sync job to create new tables, beforeSave did not run to add the additional user and token fields:

// link sale and item data Polygon
Moralis.Cloud.beforeSave("ItemsForSalePolygon", async (request) => {
  const query = new Moralis.Query("PolygonNFTOwners")
  query.equalTo("token_address", request.object.get('tokenAddress'))
  query.equalTo("token_id", request.object.get('tokenId'))
  const object = await query.first()
  if (object){
      const owner = object.attributes.owner_of
    const userQuery = new Moralis.Query(Moralis.User)
      userQuery.equalTo("accounts", owner)
    const userObject = await userQuery.first({useMasterKey:true})
    if (userObject){
        request.object.set('user', userObject);
    }
    request.object.set('token', object);
  }
})

Or is the sync job cached somehow?

For performance reasons the historical sync uses bulk insert. A side effect of this optimization is that triggers are not fired for those inserts. This explains the behavior you observed where the triggers fire on real-time inserts but not when syncing historical data.

  • You can create a job or cloud function and run it manually to take care of any initialization that needs to occur after the initial historical sync
2 Likes

I’ve made this Job:

// add token and user relations to ItemsForSale tables
Moralis.Cloud.job("addFieldsItemsForSale", async (request) =>  {
  const query = new Moralis.Query('ItemsForSale'+request.params.network)
  const itemsForSale = await query.find({useMasterKey:true})
  for (let i = 0; i < itemsForSale.length; ++i) {
    const tokenQuery = new Moralis.Query(request.params.network+'NFTOwners')
    tokenQuery.equalTo('token_address', itemsForSale[i].get('tokenAddress'))
    tokenQuery.equalTo('token_id', itemsForSale[i].get('tokenId'))
    const token = await tokenQuery.first({useMasterKey:true})
    itemsForSale[i].set('token', token)

    const userQuery = new Moralis.Query(Moralis.User)
    userQuery.equalTo('accounts', itemsForSale[i].get('address'))
    const userObject = await userQuery.first({useMasterKey:true})
    itemsForSale[i].set('user', userObject)

    await itemsForSale[i].save(null, {useMasterKey:true})
  }
})

Which works FINE if I replace the request.params.network with just ‘Eth’ for testing.
But I can’t get the requests params to work!
Am I using it wrong or is there an issue with job params?

Hey @matiyin

Can you please explain what are trying to do?
If you want to dynamicly create values you should use:

const query = new Moralis.Query(`ItemsForSale${request.params.network}`)

Thanks. Actually it works fine using my syntax everywhere in my cloud code.

The issue here is that my request params are not getting through, even when I do

logger.info(request.params.network)

nothing is returned.

What I’m doing here is to add User and Token relations to the ItemsForSale table manually, like you can do with a beforeSave trigger. Why? because when I start with a fresh empty database, the sync job does NOT add those in and I have to do it manually. Exactly as my description in the beginning of this post.

In summary: job not giving me the params I set in the UI, see sceen.

@matiyin
If the problem only in logger.info:
You should use logger.info(JSON.stringify(request.params.network))

the problem is that the request.params are not working…
forget all the rest.I have this as a test:

Moralis.Cloud.job("addFieldsItemsForSale", async (request) =>  {
  const logger = Moralis.Cloud.getLogger()
  logger.info(JSON.stringify(request.params.network))
  logger.info('testing out addFieldsItemsForSale job')
})

what I see in Logs:

and my Job setup again:

Thanks.

https://5q6ce5oht43m.moralis.io:2053/server

@matiyin

My bad, I’ve forgot about jobs specific.

You should use request.params.input.network instead of request.params.network and still need to Stringify request

P.S. use stringify only if you want to see the info in logger. In code request.params.input will work fine as a JSON object

sorry sadly still not catching it!

// add token and user relations to ItemsForSale tables
Moralis.Cloud.job("addFieldsItemsForSale", async (request) =>  {
  const logger = Moralis.Cloud.getLogger()
  logger.info(JSON.stringify(request.params.input.network))
  logger.info('testing out addFieldsItemsForSale job')
  const query = new Moralis.Query(`ItemsForSale${request.params.input.network}`)
  const itemsForSale = await query.find({useMasterKey:true})
  for (let i = 0; i < itemsForSale.length; ++i) {
    const tokenQuery = new Moralis.Query(`${request.params.input.network}NFTOwners`)
    tokenQuery.equalTo('token_address', itemsForSale[i].get('tokenAddress'))
    tokenQuery.equalTo('token_id', itemsForSale[i].get('tokenId'))
    const token = await tokenQuery.first({useMasterKey:true})
    if (token) itemsForSale[i].set('token', token)

    const userQuery = new Moralis.Query(Moralis.User)
    userQuery.equalTo('accounts', itemsForSale[i].get('address'))
    const userObject = await userQuery.first({useMasterKey:true})
    if (user) itemsForSale[i].set('user', userObject)

    await itemsForSale[i].save(null, {useMasterKey:true})
  }
})

tough cookie :sweat_smile:

@matiyin

Have you tried to run the job from there?

1 Like

yep from there it works, purfect :laughing:
cheers!