Chat app logic with Swift and Firebase - ios

I'm implementing chat logic 1-1 in my iOS app. I'm using firebase to store chats and messages in chats. Messages are working great. But I have some difficulties with chats list.
My structure of stored chats looks like this
-Users
--UserID
---chatrooms
----chatroomID
-----updatedTime
-----deleted
-----read
-----receiverID
-----receiverName
I store in NSUserDefaults NSDate value "chatsLoadedTime". I query chats by sending query:
var time: String?
if defaults.valueForKey("chatsLoadedTime") != nil {
time = "\(defaults.valueForKey("chatsLoadedTime") as! NSDate)"
}
chatsRef.queryOrderedByChild("createdTime").queryStartingAtValue(time).observeEventType(.Value, withBlock: { snap in
defaults.setValue(toLocalTime(NSDate()), forKey: "chatsLoadedTime")
and so on
.
.
.
As far as I can see it is a good way to store chats and be able to download chats from different devices. For example I have just installed the app, my chatsLoadedTime value is nil, then I download all chats and update this value to current dateTime. If new chat created, then its createdTime is bigger then my chatsLoadedTime value and the app will download it.
But I don't know how to implement a good and efficient way to delete chat. I want this logic: if user1 delete chat, then he just change his value deleted=true. If second user also delete this chat at his side, then the chat and the messages will be totally removed from the app. If user1 deleted chat, but user2 not, then if user2 write to user1, then user1 receives this messages and all previous, because messages weren't deleted. But maybe it is not the best logic. Give m, please an advice how to do this in the best way.
If I could, I would want to query on multiple values, but as far as I know it is not possible.

I've added updatedTime value to every chatRoom. And I've added a value to device called lastLoadedTime. Every time when i receive snapshot from firebase i update lastLoadedTime to current time. So, I observe chats, where time value stored on the device is smaller than updatedTime in chatRoom in firebase. When i delete chat i set updated time to 1990-01-01 00:00:00. So i won't observe this chat until somebody send me a message. Ask me if you need more information to understand :)

Related

Get firebase message from sender and receiver

I am using firebase for simple chat application. I am looking to fetch messages of user 1 and user 2. My database structure look like this.
I am using queryOrdered to fetch messages but it will filter with either sender or receiver.
Database.database().reference().child("Chats").queryOrdered(byChild: "receiver")
.queryEqual(toValue: "2WCS7T8dzzNOdhEtsa8jnlbhrl12")
.observe(.value, with: { snapshot in
})
But using this code I got messages of receiver only. How can I receive messages of sender as well. Can I use AND condition to query sender child?
There is no way in your current data structure to with a single query get both the messages that a specific user sent and received.
Firebase Database queries can only order/filter on a single property. In many cases it is possible to combine the values you want to filter on into a single (synthetic) property.
For example, you could combine the sender and receiver UID into a single properties "sender_receiver": "2WCS7T8dzzNOdhEtsa8jnlbhrl12_Sl91z...." and then query for that combined value.
For a longer example of this and other approaches, see my answer here: Query based on multiple where clauses in Firebase
For most chat applications however I recommend creating a database structure that models chat "rooms". So instead of having one long list of all messages, store the messages in rooms/threads, which is also what you show in the UI of your app.
"-RoomId1": {
"msg1": { ... },
"msg2": { ... }
}, "-RoomId2": {
"msg3": { ... },
"msg4": { ... }
}
That way you have the most direct mapping from the database, to what you show on the screen.
For a good way to name the "rooms", see Best way to manage Chat channels in Firebase
You'd then still store a mapping for each user of what rooms they're a part of, which might also be useful in securing access.

Firebase real time updates for posts from people I follow

I'm trying to get real time updates working with Firestore on my app. However, I'm not sure if what I'm trying to do is possible in real time.
I have Users who follow other Users. When they post to the Posts collection, the users timeline should be updated in real time with the posts from users they follow. Is this possible?
I have an identifier userId on each post. Any help would be appreciated as I'm a bit stuck!
You can fetch list of users that a user follows and
let queryRef = self.ref.child("posts/\(userID)")
queryRef?.observe(.childAdded, with: { (snapshot) in
// new post from a friend
})
Suppose a user john is logged In. First of all get userIDs of all the persons whom john is following. Store the userIDs in an array.
Than use an observer to listen for changes in the posts table. Whenever value of posts table is changed,
check the userID of that post.
if the array contains this userID. update the news feed of the logged In User.
Hope that helps.

Are Firebase queries scalable

In my app to check for if an email (and username) is taken when signing up I use queries like this...
let emailRef = Firebase(url: "https://photocliq5622144.firebaseio.com/users")
emailRef.queryOrderedByChild("email").queryEqualToValue(email.text!.lowercaseString).observeEventType(.Value, withBlock: { email in
Would this work well with hundreds or even thousands of users (is this scalable)?
Hundreds: yes
Thousands: yes
Tens of thousands... probably (and congratulations on the success of your app)
Hundreds of thousands... you're likely better off with a non query-based data model. For example: if you want to access some data for the user by their email address, store a map from email address to uid:
emailToUid
"HelixProbe#stackoverflow,com": "uid6479958"
"puf#stackoverflow.com": "uid209103"
With such a simple list, you can read the user's data from their email address with two direct lookups, instead of one query (which will get slower as more and more items are added).
Scalable or not is determined by your user.
Behind the scene Firebase library is just downloading JSON string and you know exactly what happen if the string is too long and the file size to be downloaded reach (for example 3MByte)
If your user is able and okay with 3MByte for a request, than you can go with it. But I don't if I am your user.

CloudKit : How to handle account changes with local persistent store?

In my application i have to maintain a local persistent store in sync with cloud kit private database. So I just wanted to know how can I handle account changes that may happen.
Confusion I have is as below:
say a set of records belong to user A now if user B log's in to the same phone I can do the following of the 2 things:
Ignore user and let data sync to B account too but that way A's data will get sync to B's private account too. Here the record change tag and all get a bit mess up since am saving CKRecord encoded fields to database.
I can maintain a user table and link each record to the user that is logged in that way user data will get separated. So should I maintain a user field along with all records ?
How can this be best handled even apart from above 2 things.
Of course in your local persistence store you could add the userID to personalize all records. An other mechanism is to remove all local data and fetch the users data when a change is detected. If you want to keep the users data on the device you could also create separate data stores for each user.
You can detect a changed login by adding the following code in your app delegate or root view controller:
NSNotificationCenter.defaultCenter().addObserverForName(NSUbiquityIdentityDidChangeNotification, object: nil, queue: nil) { _ in
/// remove local data and fetch user data
}
You should also refresh all user related data in memory and refresh the loaded views.

Custom email notifications for "Digest" type of alert subscription

I am working on a custom email notification for a WSS 3.0 solution. I am using a custom class inheriting from IAlertNotifyHandler to generate the email. There is a great example here that shows how this is done for an Immediate alert. Here is some of the code related to the SPAlertHandlerParams, which is used to get information about the alert and the item that triggered the alert.
SPAlertHandlerParams ahp;
int id = ahp.eventData[0].itemId; //gets the itemId of the item triggering the notification.
SPListItem myItem = list.GetItembyId(id);
For immediate alerts, this works great as the item I want is always at the [0] position of the eventData object. For a digest event, I thought I could just loop through all of the items in the ahp.eventData. Two problems with this.
First, it gives me all of the events where it is sending notifications, not just the ones for me. Second the eventData[0].itemId no longer points to a valid id on the list. It is 6-7 digit number instead of a 3 digit number.
Does anyone know the correct way to get to the alert information for digest emails?
Please let me know if you have any additional questions about this.
Thanks for your help!
For my project, I created a custom timer job (using the post by Andrew Connell) that mimics the Alert functionality. It runs overnight and queries for any users subscribed to my list with daily alerts. It then packages all of the new tasks into a custom email message.
I left the custom alert in place to suppress any daily notifications from the system. I just return 'True' so that alerts are not sent for tasks assigned to only 1 person. I suppose looking back on this, I could have run the query code in the custom alert and not need a separate timer job.

Resources