10

I am trying to store groups of contacts in CloudKit, and I am getting an error back if I try to create a large group of records, CKReferenced to a single group record.

The limit appears to be around 700 or so records.

Has anyone else seen a similar result, or can confirm the existence (or non-existence) of a limit? I can't find anything in the docs, or through Google.

NOTE: I am already splitting the records I submit into batches of 400 or less, as that seems to be a hard limit.

Peter Johnson
  • 3,764
  • 1
  • 23
  • 27
  • what error do you get? Is it a CKErrorCode.LimitExceeded ? First cast the record using: let errorCode:CKErrorCode = CKErrorCode(rawValue: error!.code)! – Edwin Vermeer Jan 14 '16 at 08:05
  • it is Limit Exceeded. server message = "Limit exceeded for number of owning references to single record" – Peter Johnson Jan 14 '16 at 13:13
  • If that's only 700 or so, then it would be horrible. The app that I am working on will hit that limit in production. Then instead of a CKReference, you should use a string with the ID. The only disadvantage is that you won't have automatic deletions if the parent record is removed. – Edwin Vermeer Jan 14 '16 at 14:37
  • Can you test your app with those sort of large relationships? It would be useful to see if someone else has the same problem. – Peter Johnson Jan 14 '16 at 14:38
  • I will do a test later this evening (in about 5 hours) I will also test if it varies per CKReferenceAction (non and DeleteSelf) – Edwin Vermeer Jan 14 '16 at 14:43
  • That was a nice test to do... I added a loop in my app that the moment a message was send it would do it 100 times. I had no problem adding 1000 records. Every record had 2 CKReference fields. I did send the records 1 by 1, but still in my case I did not receive any errors. I could also query the 1000 records without any problem. This is the code that I had put in a 1...100 loop: https://github.com/evermeer/EVCloudKitDao/blob/f2e6c70d4b8a1d999ee014ba642a0d5c0f04f984/AppMessage/AppMessage/Controlers/ChatViewController.swift#L208-208 – Edwin Vermeer Jan 15 '16 at 08:06
  • Thanks Edwin, that's very interesting. I'll try 1 by 1 and see if that makes a difference (I have tried in in 400s and 100s, and it refused at 400 and 700 for me in each case so it looked like maybe a 750 limit. I'll try your test code too and let you know how I get on. – Peter Johnson Jan 15 '16 at 12:55
  • I tried adding members to cloudkit individually, and it stopped at exactly 750. I tried to add another member manually using the CloudKit dashboard, and it showed "Unexpected server error. ATOMIC_FAILURE: Limit exceeded for number of owning references..." in a pop-up error message. I am using a private zone, with DeleteSelf set. Are you doing the same? – Peter Johnson Jan 15 '16 at 15:15
  • Ah, i was using a public zone. Will try a private tomorow. – Edwin Vermeer Jan 15 '16 at 16:44
  • I just saved 1000 records to my private database with 2 CKReferences to the same record. I did not encounter any error. I could find all records in the CloudKit dashboard. So there should be some special case where it goes wrong. I have all fields involved set to queryable in the dashboard. you too? – Edwin Vermeer Jan 16 '16 at 09:41
  • What happened Peter; Did you get to the bottom of this? – user3069232 Mar 04 '16 at 05:27
  • I couldn't get past the limit, i'm not sure why. it was not unreasonable for me to limit my group size to 500 contacts, anyway. – Peter Johnson Mar 04 '16 at 07:00
  • I am getting "Limit exceeded for number of owning references to single record" now also... – Jonny Dec 29 '17 at 18:25

1 Answers1

5

Yes & no - it depends on whether the CKReferences have a CKReferenceAction of deleteSelf.

In the CloudKit Web Services Reference*, Apple lists the following limit:

Maximum number of source references to a single target where the action is delete self = 750

This may explain why EVCloudKitDao was able to exceed this limit (in the comments above) - its CKReferences were previously created with a CKReferenceAction of None.

Despite the only mention of this limit being in the CloudKit Web Services documentation, the Designing for CloudKit reference links to it, and it seems to be a server-side limit that applies regardless of which CloudKit API you are using.

breakingobstacles
  • 2,815
  • 27
  • 24
  • 3
    I am having this exact issue. Thanks for the answer or I would have spent who knows how much time figuring this out. I changed it from `.DeleteSelf` to `.None` and my 1000->1 and 5000->1 CKRecord->CkReference test works fine now. However, I had to figure out how to do the cascade delete myself by hand. – Coder1224 Nov 23 '16 at 18:38
  • 1
    Unfortunately, it's either that or partition your records into logical zones (as you can delete an entire zone - and the records it contains - in a single CKModifyRecordZonesOperation.) – breakingobstacles Nov 24 '16 at 05:07
  • 1
    There is one other way around, and that is to not have a single group object, but to have a small tree of group objects (e.g. subdirectories). This is how Git and other apps avoid too many files in a directory; they use the first two letters of the file name as a directory name. You could do something similar in your CK model. – Drew McCormack Jan 10 '17 at 07:29
  • @DrewMcCormack: Have you tested that deleting the root record of a tree in which the total number of cascading deletions is greater than 750 (as a result of .deleteSelf between different references) successfully deletes all the records? What's the highest limit that you have tested? (Am curious and may dig into this to see if I can hit an internal CloudKit limit, as there appear to be for some other things.) – breakingobstacles Jan 10 '17 at 19:25
  • I have not tested this, no, so would be worth doing. But I am of the opinion that the limit has to do with some table used internally to track the cascading references, and is a per record limit. I am not aware of any limit on the total number of these references, or the number that can be triggered in a single cascade of deletions. – Drew McCormack Jan 11 '17 at 20:29
  • Thanks, this helped me... Is splitting up the kid objects really a solution (apart from goint to `.None`? I always just assumed that a "kid" object always had to be created in the same zone as its parent object... not true? – Jonny Dec 29 '17 at 18:44
  • Btw an updated link is here: https://developer.apple.com/library/content/documentation/DataManagement/Conceptual/CloudKitWebServicesReference/PropertyMetrics.html – Jonny Dec 29 '17 at 18:49
  • @Coder1224 you mean that when I change reference from `DELETESELF` to `NONE` then the limit increase to 5 000 or even more? – Bartłomiej Semańczyk Feb 12 '18 at 11:17
  • @BartłomiejSemańczyk Yes the limit goes up, possibly to unlimited?? In my case I tested with 5000 references. – Coder1224 Mar 12 '18 at 19:19
  • @Coder1224 how did you do the cascade delete? so the client not sends the server the deletes it needs? – Georg Sep 11 '18 at 18:23