Save with silent option

I was trying to save in afterSave trigger with option silent: true. But it’s still causing beforeSave to trigger and thus causing infinite loop. I am on beta branch, I see silent save option in typescript definition but not in docs.

Would you mind to share the code that you are using?

Thanks for getting back @davimacedo .

Here is the problematic code.

Parse.Cloud.beforeSave( 'Post', async request =>
{
    // Guards 
    protectWriteFields( request, [ 'createdBy', 'likesCount', 'commentsCount' ] );
    protectWriteRow( request, 'user_post_write' );
    
    // Create operation
    if ( !request.object.id )
    {
        if ( !request.user )
        {
            throw new Parse.Error( Parse.Error.OPERATION_FORBIDDEN, 'Missing user' );
        }
        request.object.set( 'createdBy', request.user );
        request.object.set( 'likeCount', 0 );
        request.object.set( 'commentCount', 0 );
    }

} );

Parse.Cloud.afterSave( 'Post', async request =>
{
        request.object.set( 'likeCount', await request.object.relation( 'likes' ).query().count( { useMasterKey: true } ) );
        request.object.set( 'commentCount', await request.object.relation( 'comments' ).query().count( { useMasterKey: true } ) );
        request.object.save( null, { useMasterKey: true, silent: true} )   
} );

The below code is actually a workaround, it’s passing signal in context if an update is required. But I was expecting that if I use the silent option in afterSave it should not trigger beforeSave.

Parse.Cloud.beforeSave( 'Post', async request =>
{
    // Guards 
    protectWriteFields( request, [ 'createdBy', 'likesCount', 'commentsCount' ] );
    protectWriteRow( request, 'user_post_write' );

    if ( !request.object.id )
    {
        if ( !request.user )
        {
            throw new Parse.Error( Parse.Error.OPERATION_FORBIDDEN, 'Missing user' );
        }
        request.object.set( 'createdBy', request.user );
        request.object.set( 'likeCount', 0 );
        request.object.set( 'commentCount', 0 );
    }
    request.context.updateCount = request.object.op( 'likes' ) != undefined || request.object.op( 'comments' ) != undefined;

} );

Parse.Cloud.afterSave( 'Post', async request =>
{
    if ( request.context.updateCount )
    {
        request.object.set( 'likeCount', await request.object.relation( 'likes' ).query().count( { useMasterKey: true } ) );
        request.object.set( 'commentCount', await request.object.relation( 'comments' ).query().count( { useMasterKey: true } ) );
        request.object.save( null, { useMasterKey: true } )
    }
} );

I don’t think this silent object when saving an object exists. Where did you find it?

The way to go is something like what you are doing: creating a stop condition. But in your specific case, I don’t see the advantage on saving it using an after save trigger. Why don’t you set this properties on beforeSave?

In typescript type definition, including docs.

Because with beforesave I have no way to check that the object that is being added is already in comments/likes relation. In that case, the relation count will remain the same.
@davimacedo If you think I am wrong about that, feel free to share your solution.

And these fields are computed for livequery.

Yes. I got your point. Maybe that’s the only way.

I think the silent option is a mistake in the typescript docs. Clients don’t get to decide whether to skip a cloud trigger or not by passing a parameter, that could be very problematic and lead to security implications.

Generally, I add this to the save hooks if I’m calling save in afterSave:

Parse.Cloud.beforeSave('TestObject', () => {

}, {
  skipWithMasterKey: true
})

Parse.Cloud.afterSave('TestObject', () => {

}, {
  skipWithMasterKey: true
})

Also count operation is not recommended. I would use increment.

1 Like

First of all many thanks @dblythy for replying.

Completely agree, I was thinking the same when I saw this option.

Great idea, but doesn’t skip for me. Not completely sure why?

I have no way to check that the object that is being added is already in comments/likes relation. So that’s why using count. If you disagree, can you share your solution?