NSPredicate to obtain Child Records

I create a CloudKit Record called Group, this record can have child records of type Category.

When I save the Category I set the record Group as it parent.


let recordIDGroup = CKRecordID(recordName: "Group", zoneID: CKRecordZoneID(zoneName: zoneName, ownerName: CKCurrentUserDefaultName))
let referenceToRecordIDGroup  = CKReference(recordID: recordIDGroup, action: .none)
let recordID = CKRecordID(recordName: name, zoneID: CKRecordZoneID(zoneName: self.zoneName, ownerName: CKCurrentUserDefaultName))
record = CKRecord(recordType: "Category", recordID: recordID)
record?.parent = referenceToRecordIDGroup
publicCloudDatabase.save(record!, completionHandler:( { savedRecord, error in
                DispatchQueue.main.async {
                        if let error = error {
                            print("accountStatus error: \(error)")
                        } else {
                            print("savedRecord recordChangeTag: \(savedRecord?.recordChangeTag)")
                        }
                    }
}))


My problem is when I want to query CloudKit to get all child records of a Group.


let recordIDGroup = CKRecordID(recordName: “Group", zoneID: CKRecordZoneID(zoneName: zoneName, ownerName: CKCurrentUserDefaultName))
let predicate = NSPredicate(format: "parent == %@", argumentArray: [recordIDGroup])
let query = CKQuery(recordType: "Category", predicate: predicate)


I get this error:


Unknown field 'CKFieldName{_name='parent’}’


How could I set up the predicate to obtain all child records of a Group?

Replies

I don't think you can query all child records using the parent property on a CKRecord - the parent-reference was added to tell a CKShare how the hierarchy of your records is structured. Also, you cannot set delete-rules on the parent reference, you need to use a different reference for that.


I would suggest that you setup the hierarchy of your records using a custom reference other than parent. This way, you can fetch for them and have delete rules to cleanup your database after deletes.


Also, have a look at Mr. Brightside's comment in this thread: https://forums.developer.apple.com/thread/64533 - when using references, you cannot have more than 750 immediate child records and a delete rule.

Hello MendelK,


My app support CloudKit Sharing and in WWDC 2016 Session 231: “ Cloudkit best practices” they said to use Parent references to support CloudKit Sharing.


- Parent references // New, To support CloudKit Sharing


- Set parent references if your app supports sharing

Photo ---------------> Album

let photoRecord = CKRecord(recordType: "Photo")

...

photoRecord.setParent(albumRecordID)

I finally solve it 🙂, by adding a field named group to the category.


let referenceToRecordIDGroup  = CKReference(recordID: recordIDGroup, action: .none)
let recordID = CKRecordID(recordName: name, zoneID: CKRecordZoneID(zoneName: self.zoneName, ownerName: CKCurrentUserDefaultName))
record = CKRecord(recordType: "Category", recordID: recordID)
record?.parent = referenceToRecordIDGroup
record?.setObject(referenceToRecordIDGroup, forKey: "group")  // This line made it works
publicCloudDatabase.save(record!, completionHandler:( { savedRecord, error in
                DispatchQueue.main.async {
                        if let error = error {
                            print("accountStatus error: \(error)")
                        } else {
                            print("savedRecord recordChangeTag: \(savedRecord?.recordChangeTag)")
                        }
                    }
}))


And with this Query predicate:


let predicate = NSPredicate(format: "group == %@", record)
let query = CKQuery(recordType: "Category", predicate: predicate)

As of today, there is no way to query records based on existing parent reference.


I believe it would be great to have this feature, especially for the first setup of sharing when you need to check that a record hierarchy is complete.


I created my radar with a request for this back in June (26939623) and I encourage you to do the same to let the CloudKit team know that we need that.