Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CloudKit: Preventing Duplicate Records

I am working through an app that pulls data from an external web service into a private CloudKit database. The app is a single user app, however I am running into a race condition that I am not sure how to avoid.

Every record in my external data has a unique identifier that I map to my CKRecord instances. The general app startup flow is:

  1. Fetch current CKRecords for the relevant record type.
  2. Fetch external records.
  3. For every external record, if it doesn't exist in CloudKit, create it via batch create (modification operation).

Now, the issue is, if this process is kicked off on two of a user's devices simultaneously, since both the CK and external fetch is async, there is a strong possibility that I'll get duplicate records.

I know I can use zones to atomically commit all of my CKRecord instances, but I don't think that solves my issue because if all of these fetches happen at essential the same time, the save is not really the issue.

My questions are:

  1. Does anyone know of a way to "lock" the private database for writes across all of a user's devices?
  2. Alternatively, is there a way to enforce uniqueness on any CKRecord field?
  3. Or, is there a way to use a custom value as the primary key, in that case I could use my external ID as the CK ID and allow the system to prevent duplicates itself.

Thanks for the help in advance!

like image 312
nickbona Avatar asked Jun 08 '15 13:06

nickbona


People also ask

How do you prevent duplicate cases in Salesforce?

In the Standard Lead Duplicate Rule, select Block instead of Allow. With the Standard Lead Duplicate Rule set to block duplicates, a rep can click to view duplicates of leads but can't save a new lead. Prevent reps from creating duplicates of records they don't have permission to view.

What is CloudKit core data?

Core Data owns the record ID for all of the objects that it creates in CloudKit. And, for each one, we will generate a simple UUID to use as its record name. When the Record Name is combined with a zone identifier you get a CKRecord ID. At the bottom, you'll see how Core Data manages type information.


1 Answers

Answers:

  1. No, you cannot lock the private database
  2. Cloudkit already enforces and assumes uniqueness of your record ID
  3. You can make the record ID anything you like (in the non zone part of it).

Explanation:

Regarding your issue of duplication. If you are the one creating the record IDs (from the external records you mentioned for example) then at worst you should have one record over write the other with the same data if you have a race condition. I do not think that is an issue for the extreme case two devices kick off this process at the same time. Basically you logic of first fetching existing records and then modifying them seems sound to me.

Code:

//employeeID is a unique ID to identify an employee
let employeeID = "001"

//Remember the recordID needs to be unique within the same database.
//Assuming you have different record types, it is better to prefix the record name with the record type so that it is unique
let recordName = "Employee-\(employeeID)"

//If you are using a custom zone
let customZoneID = CKRecordZoneID(zoneName: "SomeCustomZone", ownerName: CKCurrentUserDefaultName)
let recordIDInCustomZone = CKRecordID(recordName: recordName, zoneID: customZoneID)

//If you are using the default zone
let recordIDInDefaultZone = CKRecordID(recordName: recordName)
like image 77
harryhorn Avatar answered Sep 27 '22 22:09

harryhorn