Some properties not exist on objects inside Job

Background

I am writing a job to do small migration for some records in the database. Here is my defined Job

  Parse.Cloud.job("ParentsMigration", async (request) => {
  let userQuery = new Parse.Query(PlatformUser)
  let parentQuery = new Parse.Query(Parent)

  userQuery.equalTo("roles", PublisherRole.clientRepresentation)
  userQuery.include("belongsTo")
  let allPublishers = await userQuery.find({useMasterKey: true})

  parentQuery.equalTo("type", ParentType.Faculty)
  let allParents = await parentQuery.find({useMasterKey: true})

  for (const parent of allParents) {
    for (const publisher of allPublishers) {
      console.error(publisher.belongsTo)
      console.error(publisher.get("belongsTo"))
      if (publisher.get("belongsTo").includes(parent)) {
        parent.add("publishers",publisher)
      }
    }
    await parent.save(null,{useMasterKey: true})
  }
})

I am using ES6 classes to represent my Parse classes in my codebase. Inside each class I access the object attributes using setters and getters and here is a sample subclass

export default class PlatformUser extends Parse.User {
  constructor(attributes?: Parse.User<Attributes>) {
    super(attributes)
  }
  set roles(value) {
    this.set("roles", value)
  }

  get belongsTo(): Array<Parent> {
    return this.get("belongsTo")
  }

  set belongsTo(value) {
    this.set("belongsTo", value)
  }

 // other setters and getters

}

What is the problem
The problem is not with what the function is doing. The problem is at the lines where I do console.error(). That first console statement return undefined and for the second returns an un-completed object even though I have included the field in the query

undefined
[
  ParseObject {
    _objCount: 36,
    className: 'Parent',
    id: 'O1UvlFgQUp3P'
  }
]

Honestly I am not a Javascript/Typescript expert so It might be something related to my poor understanding of the language or it’s something related to the JS SDK (which I believe it’s not). But I don’t quite understand what is the difference between calling get(“key”) directly on the object and calling it but within a property getter

Any help will be appreciated

Did you add Parse.Object.registerSubclass('_User', PlatformUser); in some place in your code?

Do we have to do it in the backend as well? :sweat_smile:
If yes, where exactly? Because I tried to do it after I define my parse server instance but my beforeSave triggers started to throw an error
Error generating response. TypeError: Tried to create an ACL with an invalid permission type.
So I reverted the changes
here is an example on one of the triggers which throwed the previous error after I registered my subclasses in the backend:

Parse.Cloud.beforeSave(Parent.name, async (request) => {
  let authController = new AuthController()
  let client = authController.requireAuthenticatedUser(request)
  let userHasPermissions = request.master? true : await authController.checkUserHasRole(client, [PublisherRole, AdminRole])
  if (userHasPermissions) {
    request.object.setACL(ObjectSecurity.publicReadRoleWrite(AdminRole))
  } else {
    throw new Error("User don't have permissions")
  }
})

This beforeSave trigger works fine without registering subclasses in the backend

What ObjectSecurity.publicReadRoleWrite(AdminRole) returns?

static publicReadRoleWrite(role: UserRole): Parse.ACL {
    let acl = new Parse.ACL()
    acl.setPublicReadAccess(true)
    acl.setPublicWriteAccess(false)

    acl.setRoleWriteAccess(AdminRole.roleName, true)
    acl.setRoleReadAccess(AdminRole.roleName, true)
    return acl
  }

And UserRole is just an object

const AdminRole: UserRole = {roleName: "Administrator", clientRepresentation: "administrator"}

Do you know what line of code is throwing the Error generating response. TypeError: Tried to create an ACL with an invalid permission type. error?

Here is what is happening:

I have registered all of my subclasses right after I create parse server instance

Parse.Object.registerSubclass('_User', PlatformUser);
Parse.Object.registerSubclass('Post', Post);
Parse.Object.registerSubclass('Parent', Parent);
Parse.Object.registerSubclass('PostCategory', PostCategory);
Parse.Object.registerSubclass('PublisherProfile', PublisherProfile);
Parse.Object.registerSubclass('StudentProfile', StudentProfile);

If I tried to save an object (In this example object of class Parent )
I get this error

Error: Cannot read property 'getName' of undefined\n    at error (C:\my project path\node_modules\parse-server\src\triggers.js:319:16

The interesting thing here that If I removed the registration for subclasses everything will works fine and not only that. I noticed also when I register the subclasses my request.object has empty values for some fields
Here is the result of calling console.log(JSON.stringify(request.object)) when subclasses are provided

{
  "arName": "",
  "channelName": "",
  "enName": "",
  "type": "authority",
  "postCategories": [],
  "createdAt": "2021-01-02T08:18:56.364Z",
  "updatedAt": "2021-02-12T21:38:01.690Z",
  "publishers": [],
  "ACL": {
    "*": {
      "read": true
    },
    "role:Administrator": {
      "read": true,
      "write": true
    }
  },
  "objectId": "O1UvlFgQUp3P"
}

Here is the result of calling console.log(JSON.stringify(request.object)) when subclasses are not provided

{
  "arName": "النادي الياباني",
  "channelName": "par_cl_jp",
  "enName": "Japanese Club",
  "type": "club",
  "postCategories": [
    {
      "__type": "Pointer",
      "className": "PostCategory",
      "objectId": "CgJbCbfk0OAz"
    }
  ],
  "createdAt": "2021-01-02T08:18:56.364Z",
  "updatedAt": "2021-02-09T00:57:21.101Z",
  "publishers": [
    {
      "__type": "Pointer",
      "className": "_User",
      "objectId": "sPesiI4HH3OT"
    }
  ],
  "ACL": {
    "*": {
      "read": true
    },
    "role:Administrator": {
      "read": true,
      "write": true
    }
  },
  "objectId": "O1UvlFgQUp3P"
}

As you can see some fields became empty

Regarding the error related to the ACL. I already did the migration and It doesn’t make sense to me to try to reproduce the error as after what happened above I think both related to the same cause

Oh wait SO DUMB.
I think I found the source of the issue for having empty values in the record (actually it turns out that it’s a default values). In my Parent subclass. I was assigning default values for the attributes (So I can create empty objects to work with in my react frontend.) The models are located in one npm package and it’s consumed by the backend and the frontend

constructor(attributes?: Parse.Attributes) {
        super('Parent')
        this.enName = ""
        this.arName = ""
        this.channelName = ""
        this.postCategories = []
        this.publishers = []
        this.type = ParentType.Authority
    }

I guess this is the reason behind this issue. I will try again and check if the original error will disappear after applying this fix.
The reason that I didn’t find this in the beginning because I never attempted to register my subclasses in the backend so the issue went undetected for long time and also I was confused because the type of the thrown errors will let you think that it has to do with something else

While yes as I mentioned before I solved the issue with request.object value. But the first error still exist

    error: Parse error: Cannot read property 'getName' of undefined {"code":141,"stack":"Error: Cannot read property 'getName' of undefined\n    at error (C:path to my project\node_modules\parse-server\src\triggers.js:319:16)\n    at processTicksAndRejections (internal/process/task_queues.js:93:5)"}

I don’t have any property called getName on my subclasses

What is the parse server version that you are using? Could you please share the current code for this class and also for the triggers you have assigned to this class?