Why Parse push.setQuery not working on Swift? - ios

I'm trying to send a notification to the owner of a post when another user taps the "favorite" button, but I'm receiving an error:
Can't set both the query and channel (s) properties.
What can it be? My current code:
let query = PFInstallation.query()
if let query = query {
query.whereKey("installationUser", equalTo: self.job!["owner"]! as! String)
let push = PFPush()
push.setChannel("Global")
push.setMessage("Some cool text here")
push.setQuery(query)
push.sendPushInBackground()
}
The app crashes whenever I execute the line push.setQuery(query)

Remove the line push.setChannel("Global")

Related

Swift Firebase -How to generate different .childByAutoId keys when using Fan Out

I have a chat system inside my app. When the user presses send to send the message data to different nodes inside the database -it works fine. The issue I'm having is since I'm using fan out I generate the .childByAutoIdkey before the data is sent. The user presses a send button to start the process but it's always the same exact .childByAutoId key so I'm just overwriting the previous message data. If the user pops the vc and comes back to it then a new key is created but obviously that's terrible ux for a messaging system?
How can I generate different .childByAutoId keys every time the user presses send to fan out?
#obj func sendMessageButtonPressed() {
// ***here's the problem, every time they press send, it's the same exact childByAutoId().key so I'm just overwriting the previous data at the messages/messageId path
guard let messageId = FirebaseManager.Database.database().reference().child("messages")?.childByAutoId().key else { return }
var messageIdDict: [String: Any] = [messageId: "1"]
var messageDict = [String: Any]() // has the fromId, toId, message, and timeStamp on it
let messageIdPath = "messages/\(messageId)"
let fromIdPath = "user-messages/\(currentUserId)"
let toIdPath = "user-messages/\(toId)"
var fanOutDict = [String: Any]()
fanOutDict.updateValue(messageDict, forKey: messageIdPath)
fanOutDict.updateValue(messageIdDict, forKey: fromIdPath)
fanOutDict.updateValue(messageIdDict, forKey: toIdPath)
let rootRef = Database.database().reference()
rootRef?.updateChildValues(fanOutDict)
}
The problem wasn't a new key was not getting generated. #FrankvanPuffelen pointed out in th comments that a new key should get generated every time which is exactly what was happening.
The problem was the fanout was overwriting what was originally written at these 2 paths:
let fromIdPath = "user-messages/\(currentUserId)"
let toIdPath = "user-messages/\(toId)"
It appeared the key was the same because the data kept getting overwritten.
The way I was generating the key works fine

how to observe property changes of Backendless database ? - Swift

I have this code in Swift 3 to get backendless user so I can get his/her properties:
let whereClause = "objectId = '\(userId)'"
let query = BackendlessDataQuery()
query.whereClause = whereClause
let data = Backendless.sharedInstance().persistenceService.of(BackendlessUser.ofClass())
data?.find(query, response: { (result) in
let user = result?.data.first as! BackendlessUser
myLabel.text = user.getProperty("firstName") as! String
})
The code is working fine but my question is how to observe the property changes ? is there a way if the value of property firstName changed I can update my label automatically ?
The use-case you describe is not really as simple as it may seem, but it's definitely possible.
You can capture any changes in Users table by creating an afterUpdate event handler. From there you could publish a message to some dedicated channel in messaging service.
At the same time, your application should be subscribed to this same channel. This way you could update your UI when the appropriate message is received.

Receive limited query with custom start point

I'm building a basic chat app with swift for iOS with firebase realtime database.
The Messages are observed with a limit for the least 10.
Now, I want to implement the functionality of loading earlier send messages. Currently I'm trying to achieve this by using this function:
let query = threadRef.child("messages").queryOrderedByKey().queryStarting(atValue: "2").queryLimited(toLast: 2)
Which returns this query:
(/vYhNJ3nNQlSEEXWaJAtPLhikIZi1/messages {
i = ".key";
l = 2;
sp = 2;
vf = r;
})
And this should give me the data:
query.observeSingleEvent(of: .value, with: { (snap) in
But it just limits the query and not set the start point to a specific position.
Here is the firebase database structure:
messages
-Kgzb3_b26CnkTDglNd8
date:
senderId:
senderName:
text:
-Kgzb4Qip6_jQdKRWFey
-Kgzb4ha0KZkLZeBIaxW
-Kgzb577KlNKOHxsQo9W
-Kgzb5cqIVMhRmU019Jf
Anyone have an idea on how to implement a feature like that?
Okay I finally found a way to do what I wanted.
First of all I misunderstood the way to access data from Firebase.
This is now how I get the query:
let indexValue = messages.first?.fireBaseKey
let query = messageRef.queryOrderedByKey().queryEnding(atValue:indexValue).queryLimited(toLast: 3)
1) get the FireBase key I previously saved to my custom chat messages
2) construct the query:
order it by key
set the ending to oldest message
limit the array to query to desired length
Then to actually get the query I used:
query.observeSingleEvent(of: .value, with: { snapshot in
for child in snapshot.children.dropLast().reversed() {
let fireSnap = (child as! FIRDataSnapshot)
//do stuff with data
}
})
1) get the query as a single event
2) iterate over children and I needed to dropLast() to make sure I don't have any duplicated messages and reverse it to get the correct order.
3) cast the current child as a FIRDataSnapshot to access the data
Since I couldn't find a simple example for this so I thought I leave my solution here incase other people running into the same problem.

How to append without unique auto id firebase swift

I am trying to append data to my database, everytime a user is clicking a like button, if the user hasn't already clicked it. The problem is, when I am appending to the likesForPost, a unique id is showing. How can I get rid of that? Otherwise it is not possible for me to check if the user has already clicked the button?
Here is my firebase structure:
It is the green parts that are unique id, the black zones under the unique id are the user id, that I want to be able to check if has already clicked the button.
This is my code for appending to likesForPost
let quoteString = [userId: true]
let refPhotos = FIRDatabase.database().reference().child("feed-items").child(dataPathen).child("likesForPost")
let refBase54 = refPhotos.childByAutoId()
refBase54.setValue(quoteString)
Hope you guys can help me :-)
Use :-
let prntRef = FIRDatabase.database().reference().child("feed-items").child(dataPathen).child("likesForPost")
prntRef.observeSingleEventOfType(.Value, withBlock: { (snap) in
if let favDict = snap.value as? NSMutableDictionary{
favDict.setObject("true",forKey : uid)
prntRef.setValue(favDict)
} else {
prntRef.setValue(["true":uid])
}
})
Or But this is just a HACK!
FIRDatabase.database().reference().child("feed-items").child(dataPathen).child("likesForPost").updateChildValues(quoteString)
For more options check:- https://stackoverflow.com/a/39458044/6297658

Sending and receiving push notification swift

I created a small messenger app using Parse as my database in swift. I wanted each time any user sends a message only other users within 10 meter to get the notification. The app is working but the push notification is not. I did some research it looks like my code is similar to the one i found but still not working. Please help me. Thank you
var CurrentLocation : PFGeoPoint = PFGeoPoint(latitude: 44.6854, longitude: -73.873) // assume the current user is here
let userQuery = PFUser.query()
userQuery?.whereKey("Location", nearGeoPoint: CurrentLocation, withinMiles: 10.0)
let pushQuery = PFInstallation.query()
pushQuery?.whereKey("username", matchesQuery: userQuery!)
let push = PFPush()
push.setQuery(pushQuery)
push.setMessage(" New message")
push.sendPushInBackground()
Your problem is the line pushQuery?.whereKey("username", matchesQuery: userQuery!). According to the parse docs Warning: This only works where the key’s values are PFObjects or arrays of PFObjects. Read more here: https://parse.com/docs/osx/api/Classes/PFQuery.html#//api/name/whereKey:matchesQuery
Instead change it to chain the query by first performing the first query and then using the strings of the userIds for the second query which is performed inside the first's completionBlock.
Update
Also, just as a side note you are not abiding by the camel case rules of swift and also the rules set out by Parse. You should follow conventions. (See my code for the correct case for keys in Parse and variable names).
Example:
var currentLocation : PFGeoPoint = PFGeoPoint(latitude: 44.6854, longitude: -73.873) // assume the current user is here
let userQuery = PFUser.query()
userQuery?.whereKey("location", nearGeoPoint: currentLocation, withinMiles: 10.0) // Note I changed Location to location
userQuery?.findObjectsInBackground({ results, error in
let usernames = (results as! [PFObject]).map { $0.username }
let pushQuery = PFInstallation.query()
pushQuery?.whereKey("username", containedIn: usernames)
let push = PFPush()
push.setQuery(pushQuery)
push.setMessage("New message")
push.sendPushInBackground()
})
Also note that you may need to change your structure because the docs for PFInstallation.query note that you must use one of three query parameters and you are using none (you might have to save the installation object id to a field on the user. Then instead of making an array with username make an array with the installation object ids and query PFInstallation like that. However, this may still work so try it first, you never know.

Resources