Some questions about CloudKit - ios

record type: Country(CKRecord)
--------------------
name: String
code: String
--------------------
record type: User(CKRecord)
------------------------
name: String
country: CKReference (reference to country record>
-------------------------
I have 2 record types (Country and User) created by CloudKit Dashboard. I encountered some cloudkit issues.
currently! I query User and then using country reference to fetch country record. When I using cloudKit to get some records
I have to do a lot of queries and fetches that waste a lot of time for waiting. so my issues are
1)How to get User record and Country record at the same time, If I query a record? example: query User Record
2)In some record that have a reference list. How to delete a CKReference in that reference list
Thanks a lot

In CloudKit there is no way to query 2 different recordTypes in 1 query. The only exception is when you already know the specific RecordId's. Then you could query for those ID's. So In your case, when you don't already know the User, you do have to do 2 queries to get the country record.
You could limit the number of fetches since you probably have a limited number of countries. At app startup just query all the countries and save them somewhere in memory, then when you do query for a user, you can get the country from memory. If you suspect that your country data will change frequently, then create a subscription so that you get a notification to update your data in memory.
If you have a reference list in your record, then query that record, remove the item from the list and save that record again.

Related

Firestore Map field performance with large dataset

I have a list of products, each user can buy multiple tickets for a product. When I fetch a product I need to know how many tickets a user has bought per product. I currently have product as a separate collection and I fetch a list of tickets per products for the current logged in user. This worked great but I was using an in statement to make a single query to fetch the tickets in a single query for multiple products, and Firestore only allows 10 items in an in statement
I'm considering storing the count of tickets on each product as a map. How does this affect the performance of the snapshotListener? Let's say I listen to 100 products and each has a Map with 100k key-values where the key is a string and the value is an Int.
Is it easy to update the map, can i do an increment on the value of a specific field?
Security is not an issue, it's ok to have the ticket count for all users public
Product {
name: String
....
tickets: {
"USERID": 5,
// 100k more records
}
}
I'm considering storing the count of tickets on each product as a map. How does this affect the performance of the snapshotListener?
It has no effect on the performance of anything other than the time it takes to download the document.
Is it easy to update the map, can i do an increment on the value of a specific field?
Yes, it's easy. Use dot notation to locate the field to increment, and use FieldValue.increment() to increment it.

CloudKit query for reference in array

Let's say I have two CloudKit record types:
Company
name (string)
etc...
Employee
first name (string)
etc...
company (reference to Company)
In my app if I have an array Companies, is there a way to query CloudKit for all Employees whose company is in this array with a single query? Obviously I could go through the companies array and query one by one, but if this array is large then that's going to be a lot slower.
The docs say that you can reference an array in a CKQuery predicate, but doesn't say how.
Yes you can use the predicate
NSPredicate(“%k IN %#“, company, arrayofcompaniesReference)
company is the key in employee record type
arrayOfCompaniesReference is the array of reference of companies you have.

How to fetch records from a specific record zone

I'm building an app that allows users to manage their products in the cloud.
To do this, I have a Product Record type in iCloud. I use this record type for two purposes:
To manage the products I have available, all stored in a dedicated Products record zone
To save products I have stored in checks from customers. I have a separate Checks record zone, in which I save checks or 'receipts' from transactions made with customers. I use the Product record type here too, in order to keep track of what products are being sold.
Now I have one problem: When I try to fetch all products for my product manager, it also fetches the products from the Checks record zone - the zone containing the transactions and the products they contain. I obviously need to fetch only the products from the Products Record Zone.
There doesn't seem to be much reference for this on the internet, so I figured I'd post a question here for, also for future reference.
Is there a way in CloudKit to fetch records from a specific record zone?
You could use a CKQueryOperation and set the zoneID like this:
let operation = CKQueryOperation(query: query)
operation.zoneID = CKRecordZoneID(zoneName: "name", ownerName: "me")

What is the best practice approach to fetching CKReferences in CloudKit?

In my CloudKit setup I have a Person record type and each person has a Friend attribute which is a CKReference to another Person object.
I fetch all Person CKRecords. I list these people in a table and list their friends with them. Currently I just take the CKReference and individually fetch each friend using the recordID.
This is the only way I can see to do it, but what would be best practice? Particularly as I am fetching potentially a very large number of friends. It seems counterintuitive to fetch all these objects individually.
I was wondering if there was a method much like CoreData, where you can choose to fetch related objects in the main fetch? So for example, when I fetch a Person it automatically fetched the friends too.
You could use an 'in' predicate query to fetch multiple id's. You can define a predicate like this:
NSPredicate(format: "To_ID in %#", [recordIdMe, recordIdOther])!
In your case where you see the recordIdMe and recordIdOther you should have an array of valid CKReference objects.
In CloudKit there is no functionality to automatically fetch related records.
Actually you should collect all the RecordIDs and add a CKFetchRecordsOperation to the relevant database object.
You get a back a dictionary to help you match the results with the original list.

discoverAllContactUserInfosWithCompletionHandler returning multiple records for same user?

When I invoke discoverAllContactUserInfosWithCompletionHandler: the returned array of CKDiscoveredUserInfo has three distinct userRecordIDs but these are all for a person with the same firstName + lastName. The three userRecordIDs share the same recordName but differ by zoneID. As best I can figure this is the same person with three 'iCloud' email addresses: icloud.com, me.com, mac.com. Presenting all three in my App's UI is a non-starter given that they are indistinguishable.
Is there any reason to choose one of the multiple records over another? Is my presumption that they are indeed different iCloud mail addresses correct? Can I go from userRecordID to email?
[I know the email accounts; presumably I could query with discoverUserInfoWithEmailAddress:completionHandler and correlate the results myself.
The recordName is the only part that really matters here, but it's odd that the userRecordIDs have different zoneIDs. They should all be in the default public zone, so you might be hitting a bug. What zone IDs are you seeing?
If you have to pick one record ID, go with the one in -[CKRecordZone defaultRecordZone]

Resources