Ckquery from Private Zone Returns Only First 100 Ckrecords from in Cloudkit

CloudKit private database returns first 100 CKRecords

Ok, i found a solution. See below:

func loadDataFromCloudKit() {
var results: [AnyObject] = []
let cloudContainer = CKContainer.defaultContainer()
let privateDatabase = cloudContainer.privateCloudDatabase

let predicate = NSPredicate(value: true)
let query = CKQuery(recordType: "Data", predicate: predicate)
query.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: true)]

let queryOperation = CKQueryOperation(query: query)
queryOperation.desiredKeys = ["id","name"]
queryOperation.queuePriority = .VeryHigh
// Max limit is still 100
queryOperation.resultsLimit = 100

queryOperation.recordFetchedBlock = { (record:CKRecord!) -> Void in
results.append(record)
}

queryOperation.queryCompletionBlock = { (cursor, error) in
dispatch_async(dispatch_get_main_queue()) {
if (error != nil) {
print("Failed to get data from iCloud - \(error!.localizedDescription)")
} else {
print("Successfully retrieve the data form iCloud")

}
}
// see cursor here, if it is nil than you have no more records
// if it has a value than you have more records to get
if cursor != nil {
print("there is more data to fetch")
let newOperation = CKQueryOperation(cursor: cursor!)
newOperation.recordFetchedBlock = { (record:CKRecord!) -> Void in
results.append(record)
}

newOperation.queryCompletionBlock = queryOperation.queryCompletionBlock
privateDatabase.addOperation(newOperation)
} else {
// gets more then 100
print(results.count)
}
}
privateDatabase.addOperation(queryOperation)
}

CloudKit Query Operation only returns 300 results

Could you try setting:

queryOperation.qualityOfService = .UserInitiated

This will indicate that your user interaction requires the data.
Otherwise it could happen that de request is ignored completely.

As discussed below the actual answer was that you should not re-use completion blocks. Instead you should create a recursive function for fetching the next records from a cursor. A sample of that can be found at: EVCloudKitDao

Why will my CKQueryOperation only return a Cursor if the results limit is less than 1000?

I believe that 400 is the the limit for a single operation, so you need to use cursor to get more records, and keep on doing that while returned cursor is not nil.

See how it is done in RxCloudKit library' RecordFetcher -
https://github.com/maxvol/RxCloudKit/blob/master/RxCloudKit/RecordFetcher.swift

Swift CloudKit and CKQuery: how to iteratively retrieve records when queryResultBlock returns a query cursor

No need for queryResultBlock in Swift 5.5.

I use this because my CKRecord types are always named the same as their Swift counterparts. You can replace recordType: "\(Record.self)" with your recordType if you want, instead.

public extension CKDatabase {
/// Request `CKRecord`s that correspond to a Swift type.
///
/// - Parameters:
/// - recordType: Its name has to be the same in your code, and in CloudKit.
/// - predicate: for the `CKQuery`
func records<Record>(
type _: Record.Type,
zoneID: CKRecordZone.ID? = nil,
predicate: NSPredicate = .init(value: true)
) async throws -> [CKRecord] {
try await withThrowingTaskGroup(of: [CKRecord].self) { group in
func process(
_ records: (
matchResults: [(CKRecord.ID, Result<CKRecord, Error>)],
queryCursor: CKQueryOperation.Cursor?
)
) async throws {
group.addTask {
try records.matchResults.map { try $1.get() }
}

if let cursor = records.queryCursor {
try await process(self.records(continuingMatchFrom: cursor))
}
}

try await process(
records(
matching: .init(
recordType: "\(Record.self)",
predicate: predicate
),
inZoneWith: zoneID
)
)

return try await group.reduce(into: [], +=)
}
}
}

CloudKit returns too many records

I just found out, that there is a bug in CloudKit, that deleted records are somehow hidden still available. I resetted my development environment and imported the data again and I got the correct amount of records returned.

More information can be found in this Stackoverflow post:
Deleted CloudKit records Reappear

Can I receive count of records corresponding to CKQuery from CloudKit?

Aggregation queries are not possible in CloudKit. So you have to query all records and count those. To make sure that all records will be returned, you have to set operation.resultsLimit to a value larger than the count otherwise it could happen that not all records are returned.



Related Topics



Leave a reply



Submit