Cloud kit: how to get public database subscription notification from your group of contacts only - cloudkit

I have CKRecord for Location details in the public database. I want to create a subscription for a CKrecord with location details, stored in the public database. I want to set subscription so I get notification from those that are in my contacts group only. The subscription notification on Location CKrecord notifies me on all users which takes more time to sort through and I want to avoid this.
How can I set the subscription?

Assuming your Location recordType has some kind of userEmail field on it, you can query for those records like this:
let predicate = NSPredicate(format: "userEmail = %#", argumentArray: ["name#example.com"])
let query = CKQuery(recordType: "Location", predicate: predicate)
let operation = CKQueryOperation(query: query)
var records = [CKRecord]()
operation.recordFetchedBlock = { record in
records.append(record)
}
operation.queryCompletionBlock = { cursor, error in
print("Done.")
print(records)
}
CKContainer(identifier: "iCloud.yourContainer").publicCloudDatabase.add(operation)

Related

Firebase firestore getting data from inside collection

Is there a way to grab the data from owner ID I'm not able to access the collection oath because the documentID is auto-generated and not a specific value I have control of
A possible option would be to query your documents and retrieve a specifc OwnerID like this.
If you want to fetch all OwnerIDs from all of your documents just remove the 'whereField'.
Also check out the Firebase documentation for queries.
let docRef = db.collection("YOURCOLLECTIONNAME")
let query = docRef.whereField("OwnerID", isEqualTo:"VAL")
query.getDocuments{ (querySnapshot, error) in
if let error = error {
print("\(error.localizedDescription)")
}else {
for documents in (querySnapshot?.documents)! {
if let owner = documents.get("OWnerID") as? String {
print(owner)
}
}

How to Fetch Records from CloudKit Not in My Local Cache

I have an app that uses CloudKit for sync and I maintain a local cache of records. I have run into a sync scenario that I can't figure out.
I'm using the Public database and when my app is opened, I want to be able to go get all the updated records that my app missed while it was closed, or on a device where the app was just installed.
I can get the updated records by creating a NSPredicate to compare the modificationDate like this:
let predicate = NSPredicate(format: "modificationDate > %#", syncTimestamp as CVarArg)
let query = CKQuery(recordType: recordType, predicate: predicate)
But the part I can't figure out is how to get only the records that have been added to, or removed from, the CloudKit server.
Does anyone know how to do this? I know Apple provides a way for this in the Private database but I'm using the Public one here.
The only thing I can think of so far is to query all the reocrds of a certain recordType, collect all their recordNames and compare to my local cache. But it'd be nice to have smarter way than just pull large amounts of data and comparing huge arrays of recordNames.
CKQuerySubscription(recordType: myRecordType, predicate: predicate, options: [.firesOnRecordCreation, .firesOnRecordDeletion]) works perfectly on public DB.
Here's a code snippet (saving subscription is done with RxCloudKit, but this is beyond the point) -
let predicate = NSPredicate(format: "TRUEPREDICATE")
// the options are different from what you need, just showcasing the possibilities:
let subscription = CKQuerySubscription(recordType: recordTypeTest, predicate: predicate, options: [.firesOnRecordCreation, .firesOnRecordUpdate, .firesOnRecordDeletion, .firesOnce])
let info = CKNotificationInfo()
info.alertLocalizationKey = "NEW_PARTY_ALERT_KEY"
info.soundName = "NewAlert.aiff"
info.shouldBadge = true
subscription.notificationInfo = info
self.publicDB.rx.save(subscription: subscription).subscribe { event in
switch event {
case .success(let subscription):
print("subscription: ", subscription)
case .error(let error):
print("Error: ", error)
default:
break
}
}.disposed(by: self.disposeBag)

Swift saving new comments using CloudKit

I'm trying to make an app which stores a user's comment on CloudKit and then shows it to the other users. User simply enters his/her comment on a text field and clicks on a submit button to submit his/her comment (just like a restaurant app). However, I can't seem to find the correct way no matter what I try. Here is my code, I'd be very glad for any help as I've been stuck on this problem for some time now. Thank you very much in advance!
#IBAction func OnSubmitTouched(_ sender: UIButton) {
if (textField.text != ""){
let newComment = CKRecord(recordType: "Users")
let publicDB = CKContainer.default().publicCloudDatabase
newComment.setValue(textField.text!, forKey: "comment")
publicDB.save(newComment){
rec ,err in
if let error = err {
print(err.debugDescription)
return
}
publicDB.fetch(withRecordID: newComment.recordID){
rec, err in
print(rec!["comment"]!)
return
}
}
let predicate = NSPredicate(value: true)
let query = CKQuery(recordType: "comment", predicate: predicate)
let operation = CKQueryOperation(query: query)
var commentRecords: [CKRecord] = []
operation.recordFetchedBlock = { record in
commentRecords.append(record)
}
operation.queryCompletionBlock = { cursor, error in
print(commentRecords)
}
CKContainer.default().publicCloudDatabase.add(operation)
}
}
You are getting a permission error because Users is a protected record type that CloudKit creates automatically for users of your app. You should name it something else and then it should work.
For example, you could make a Comment record type. This might need a field that references the current user. You can get the current userID with:
CKContainer fetchUserRecordIDWithCompletionHandler:
Here is the Apple documentation for this method.
It is also possible to use the Users record type, but you would have to find the existing userID from CloudKit as above then build a record around that.
See also this answer.

CKQuery with CloudKit Issue

I'm very new to CloudKit and am simply trying to run the most basic query. I want to pull from RecordType "Users" and field type "Name" and have the name equal to my nameText label!
Please see my code below:
func getUserInformation() {
let Pred = NSPredicate(value: true)
let Query = CKQuery(recordType: "Namer", predicate: Pred)
let AgeOp = CKQueryOperation(query: Query)
AgeOp.database = self.Pub
AgeOp.recordFetchedBlock = {(record : CKRecord!) in
let Recorded : CKRecord = record!
self.nameText.text = Recorded.objectForKey("Name") as? String
}
}
override func viewDidLoad() {
super.viewDidLoad()
self.Container = CKContainer.defaultContainer() as CKContainer
self.Pub = Container.publicCloudDatabase as CKDatabase
self.Container.accountStatusWithCompletionHandler {
accountStatus, error in
if error != nil {
print("Error: \(error?.localizedDescription)")
} else {
self.getUserInformation()
}
}
}
Users is a system table. You could add new fields to that, but it's advised not to do so. One of the main reasons is that you cannot query the Users recordType.
Besides that I see in your code that you query the recordType Namer and not Users. Is your question wrong or is your code wrong?
In the recordFetchedBlock you directly put the result in the .text. That block will be executed in a background thread. You should first go to the mainQueue. You could do that like this:
AgeOp.recordFetchedBlock = {(record : CKRecord!) in
NSOperationQueue.mainQueue().addOperationWithBlock {
let Recorded : CKRecord = record!
self.nameText.text = Recorded.objectForKey("Name") as? String
}
}
When there is no query match, then the .recordFetchedBlock will never be called. You should also set the .queryCompletionBlock
The query could return multiple records (if there are more people with the same name). In the recordFetchedBlock you should add records to an array. Then in the .queryCompletionBlock you could use that array.

recordFetchedBlock on CKQueryOperation not being called

I need to query for CKRecords of the recordType "Event". When I call recordFetchedBlock, I will add those records to my array. However, recordFetchedBlock is never getting called. Please help! Thank you:
//TODO: Query for all Event records
var database: CKDatabase = CKContainer.defaultContainer().privateCloudDatabase
let truePredicate = NSPredicate(value: true)
let eventQuery = CKQuery(recordType: "Event", predicate: truePredicate)
let queryOperation = CKQueryOperation(query: eventQuery)
queryOperation.recordFetchedBlock = { (record : CKRecord!) in
self.eventsArray.append(record)
println("recordFetchedBlock: \(self.eventsArray)")
}
queryOperation.queryCompletionBlock = { (cursor : CKQueryCursor!, error : NSError!) in
println("queryCompletionBlock: \(self.eventsArray)")
}
database.addOperation(queryOperation)
So I just realized my error. I was accidentally calling the query on the private database (as opposed to the public). Currently kicking myself..