Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CloudKit - How to Save Record If Not Exists

I am trying to make a Record Type that contains unique values, and would act as the target reference objects to another Record Type. For example, Record Type - Movies would contain unique list of movies submitted by users. And FavoriteMovies would contain a Users reference and a Movies reference. Users could select from a list of existing Movies, or add new ones to it.

The problem happens if I create a new Movies record, while another user creates a new record with the same name (after I retrieved the list of movies, but before I attempt to add a new one). The two new records are considered different records with different recordIDs. This means that once I saved the new one, there will be two instances of Movies with the save name.

I'm not able to find a way to perform a Save If Not Exists type operation to the Movies Record Type. I could do a save in the completionBlock of a query, but those two actions would not be an atomic transaction to guarantee uniqueness. As far as I know this is also the case with chaining CKQueryOperation with CKModifyRecordsOperation.

Is there a way to insert a record only if the value does not exists in a single transaction?

like image 428
Denis Avatar asked Jul 16 '14 15:07

Denis


1 Answers

If I understood correctly your use case, you can make movieRecord.recordID.recordName the movie's name and use CKModifyRecordsOperation with savePolicy IfServerRecordUnchanged to effectively Save If Not Exists. It would then return an error that you can ignore if you try to save a record that already exists on the server:

let saveRecordsOperation = CKModifyRecordsOperation()
saveRecordsOperation.recordsToSave = [movieRecord]
saveRecordsOperation.savePolicy = .IfServerRecordUnchanged

With the savePolicy IfServerRecordUnchanged this operation will save a new Movie record if it doesn't exist yet on the server (Save If Not Exists) but will return the error below on any subsequent try to overwrite a Movie record that already exists on the server (provided it is not a newer modified version of a record that was fetched from the server):

<CKError 0x14d23980: "Server Record Changed" (14/2017); server message = "record to insert already exists">

You could deal with this conflict in the perRecordCompletionBlock but in your specific use case you can just do nothing about the conflict error so each Movie record will be the first saved record with that CKRecordID.

like image 143
Guto Araujo Avatar answered Oct 18 '22 00:10

Guto Araujo