Search code examples
swiftparse-platformparse-server

Fetch several ParseObjects with objectId


I am updating an iOS app using ParseSwift. In general, every ParseUser of the app has several associated Userdata ParseObjects that need to be queried or fetched.

The current implementation uses individual queries to find every individual Userdata object one after the other. This works but is obviously not optimal.

What I already reworked is that every ParseUser now saves an Array of objectId's of the user-associated Userdata ParseObjects.

What I am trying to achieve now is to query for all Userdata objects that correspond to these saved objectId's in the ParseUser's userdataIds field.

This is my code:

func asyncAllUserdataFromServer() {
    let userdataIdArray = User.current!.userdataIds

    var objectsToBeFetched = [Userdata]()

    userdataIdArray?.forEach({ objectId in
        let stringObjectId = objectId as String
            
        // create a dummy Userdata ParseObject with stringObjectId
        let object = Userdata(objectId: stringObjectId)
            
        // add that object to array of Userdata objects that need to be fetched
        objectsToBeFetched.append(object)
    })
        
    // fetch all objects in one server request
    objectsToBeFetched.fetchAll { result in
        switch result {
        case .success(let fetchedData):
            
        // --- at this point, fetchedData is a ParseError ---
        // --- here I want to loop over all fetched Userdata objects ---

        case .failure(let error):
            ...
        }
    }
}

I read in the ParseSwift documentation that several objects can be fetched at the same time based on their objectIds, so my idea was to create an Array of dummy Userdata objects with the objectIds to fetch. This, however, does not work.

As indicated in the code block, I was able to narrow the error down, and while the query is executed, fetchedData comes back as a ParseError saying:

Error fetching individual object: ParseError code=101 error=objectId "y55wmfYTtT" was not found in className "Userdata"

This Userdata object with that objectId is the first (and only) objectId saved in the User.current.userdataIds array. This object does exist on my server, I know that for sure.

Any ideas why it cannot be fetched?

General infos:

  • Xcode 13.2.1
  • Swift 5
  • ParseSwift 2.5.0
  • Back4App backend

Edit:

User implementation:

struct User: ParseUser {

    //: These are required by `ParseObject`.
    var objectId: String?
    var createdAt: Date?
    var updatedAt: Date?
    var ACL: ParseACL?

    //: These are required by `ParseUser`.
    var username: String?
    var email: String?
    var emailVerified: Bool?
    var password: String?
    var authData: [String: [String: String]?]?

    //: Custom keys.
    var userdataIds: [String]?  // --> array of Userdata objectId's

}

Userdata implementation:

struct Userdata: ParseObject, ParseObjectMutable {
    
    var objectId: String?
    var createdAt: Date?
    var updatedAt: Date?
    var ACL: ParseACL?
    
    var firstname: String?
    var lastSeen: Int64?
    var isLoggedIn: Bool?
    var profilepicture: ParseFile?
    
}

Solution

  • You should check your Class Level Permissions (CLP's) and here in Parse Dashboard, if you are using the default configuration, you can’t query the _User class unless you make the CLP’s public or authorized. In addition, you can probably shrink your code by using a query and finding the objects instead of building your user objects and fetching the way you are doing:

    let userdataIdArray = User.current!.userdataIds
    let query = Userdata.query(containedIn(key: "objectId", array: userdataIdArray))
    
    //Completion block
    query.find { result in
      switch result {
      case .success(let usersFound):
        ...
      case .failure(let error):
        ...
      }
    }
    
    // Async/await
    do {
      let usersFound = try await query.find()
      ...
    } catch {
      ...
    }
    

    You should also look into your server settings to make sure this option is doing what you want it to do: https://github.com/parse-community/parse-server/blob/4c29d4d23b67e4abaf25803fe71cae47ce1b5957/src/Options/docs.js#L31