{"id":45707,"date":"2024-11-07T13:58:33","date_gmt":"2024-11-07T18:58:33","guid":{"rendered":"https:\/\/mjtsai.com\/blog\/?p=45707"},"modified":"2026-04-17T08:32:09","modified_gmt":"2026-04-17T12:32:09","slug":"cloudkit-reference-and-index-issues","status":"publish","type":"post","link":"https:\/\/mjtsai.com\/blog\/2024\/11\/07\/cloudkit-reference-and-index-issues\/","title":{"rendered":"CloudKit Reference and Index Issues"},"content":{"rendered":"<p><a href=\"https:\/\/wwdcnotes.com\/documentation\/wwdcnotes\/wwdc14-231-advanced-cloudkit\/\">Kuba Suder<\/a>:<\/p>\n<blockquote cite=\"https:\/\/wwdcnotes.com\/documentation\/wwdcnotes\/wwdc14-231-advanced-cloudkit\/\">\n<p>CloudKit also automatically creates indexes for each field in each record type - when you&rsquo;re done with development, you can delete some indexes that you won&rsquo;t need so they don&rsquo;t waste space in the production database.<\/p>\n<\/blockquote>\n\n<p><a href=\"https:\/\/developer.apple.com\/library\/archive\/documentation\/DataManagement\/Conceptual\/CloudKitWebServicesReference\/QueryingRecords.html\">Apple<\/a>:<\/p>\n<blockquote cite=\"https:\/\/developer.apple.com\/library\/archive\/documentation\/DataManagement\/Conceptual\/CloudKitWebServicesReference\/QueryingRecords.html\">\n<p>A request to fetch records performs a query on indexed fields for a particular record type. At least one field in the record needs to be indexed to perform an empty query that fetches all records. Because indexes are updated asynchronously, they are not guaranteed to be current.<\/p>\n<\/blockquote>\n\n<p><a href=\"https:\/\/stackoverflow.com\/questions\/34824301\/in-cloudkit-after-adding-a-record-the-new-record-will-not-appear-in-a-query-th\">Eric Zinda<\/a>:<\/p>\n<blockquote cite=\"https:\/\/stackoverflow.com\/questions\/34824301\/in-cloudkit-after-adding-a-record-the-new-record-will-not-appear-in-a-query-th\"><p>The solution is to use <code>CKFetchRecordChangesOperation<\/code>, if the data is in a custom zone of the private database. If you are using the public database, or the default zone of the private database, think about this:<\/p><ol><li>The device making the changes knows the changes. [meaning: keep a cache of the updates you make]<\/li><li>The other peer devices observe the changes using CKQuerySubscription.<\/li><\/ol><\/blockquote>\n\n<p><a href=\"https:\/\/blog.justtact.com\/cloudkit-reference-queries\/\">Jaanus Kase<\/a>:<\/p>\n<blockquote cite=\"https:\/\/blog.justtact.com\/cloudkit-reference-queries\/\">\n<p>This is one of those posts, exploring how querying based on <a href=\"https:\/\/developer.apple.com\/documentation\/cloudkit\/ckrecord\/reference\">CKReference<\/a> works, and what are the limits and behaviors of that.<\/p>\n<p>[&#8230;]<\/p>\n<p>Here is one important bit: <strong>you can&rsquo;t do queries by <code>parent<\/code> property.<\/strong> I couldn&rsquo;t immediately find the authoritative source for this in the SDK documentation, but the recommendation in Apple forums and elsewhere has always been to add your own <code>CKReference<\/code> fields if you want to query by parent record.<\/p>\n<p>[&#8230;]<\/p>\n<p>The key bit is the predicate for the reference set. I got the idea for setting up this way from <a href=\"https:\/\/stackoverflow.com\/questions\/46194819\/use-contains-or-any-in-cloudkit-predicate-with-an-array-of-comparison\">this StackOverflow post.<\/a> The official CloudKit documentation does have examples for querying based on references, but not reference sets and more complex scenarios.<\/p>\n<p>[&#8230;]<\/p>\n<p>Fair enough. This tells me that the filtering condition in the clause <code>ANY %@ in relatedRecords<\/code> can&rsquo;t contain more than 250 objects. So, let&rsquo;s limit it, leave some headroom, and run it with 200 records instead.<\/p>\n<p>[&#8230;]<\/p>\n<p>Even though the input contains only 200 objects, I get this error. I speculate that even though the input amount is below the nominal stated limit, some relationship query to construct the results causes some internal limit overflow on the CloudKit side, and it doesn&rsquo;t handle this situation well.<\/p>\n<\/blockquote>\n\n<p><a href=\"https:\/\/www.caseyliss.com\/2024\/10\/22\/weird-cloudkit-issue\">Casey Liss<\/a>:<\/p>\n<blockquote cite=\"https:\/\/www.caseyliss.com\/2024\/10\/22\/weird-cloudkit-issue\">\n<p>Thinking about this some more, and in chatting with the good samaritans on\nSlack, we all came to the same conclusion: the index probably didn&rsquo;t properly&#8230;\nuh&#8230; <em>index<\/em>&#8230; whatever data was already there before the index was created.<\/p>\n<p>So, if you&rsquo;re ever in a situation where you&rsquo;re getting wonky results (or no results at all) from a new field in CloudKit, consider whether the data you&rsquo;ve added was done so before or after you added the corresponding index.<\/p>\n<\/blockquote>\n\n<p>Previously:<\/p>\n<ul>\n<li><a href=\"https:\/\/mjtsai.com\/blog\/2024\/05\/29\/cloudkit-throttles-and-debugging\/\">CloudKit Throttles and Debugging<\/a><\/li>\n<li><a href=\"https:\/\/mjtsai.com\/blog\/2023\/01\/18\/icloud-syncing-limitations-solutions\/\">iCloud Syncing Limitations &amp; Solutions<\/a><\/li>\n<\/ul>","protected":false},"excerpt":{"rendered":"<p>Kuba Suder: CloudKit also automatically creates indexes for each field in each record type - when you&rsquo;re done with development, you can delete some indexes that you won&rsquo;t need so they don&rsquo;t waste space in the production database. Apple: A request to fetch records performs a query on indexed fields for a particular record type. [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"apple_news_api_created_at":"2024-11-07T18:58:36Z","apple_news_api_id":"1b2d26a1-8c86-4f2e-85d6-0063e38940e0","apple_news_api_modified_at":"2024-11-07T18:58:36Z","apple_news_api_revision":"AAAAAAAAAAD\/\/\/\/\/\/\/\/\/\/w==","apple_news_api_share_url":"https:\/\/apple.news\/AGy0moYyGTy6F1gBj44lA4A","apple_news_coverimage":0,"apple_news_coverimage_caption":"","apple_news_is_hidden":false,"apple_news_is_paid":false,"apple_news_is_preview":false,"apple_news_is_sponsored":false,"apple_news_maturity_rating":"","apple_news_metadata":"\"\"","apple_news_pullquote":"","apple_news_pullquote_position":"","apple_news_slug":"","apple_news_sections":"\"\"","apple_news_suppress_video_url":false,"apple_news_use_image_component":false,"footnotes":""},"categories":[4],"tags":[131,916,16,31,2586,71],"class_list":["post-45707","post","type-post","status-publish","format-standard","hentry","category-programming-category","tag-bug","tag-cloudkit","tag-icloud","tag-ios","tag-ios-18","tag-programming"],"apple_news_notices":[],"_links":{"self":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/45707","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/comments?post=45707"}],"version-history":[{"count":3,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/45707\/revisions"}],"predecessor-version":[{"id":51621,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/posts\/45707\/revisions\/51621"}],"wp:attachment":[{"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/media?parent=45707"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/categories?post=45707"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/mjtsai.com\/blog\/wp-json\/wp\/v2\/tags?post=45707"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}