I am trying to loop through the participants of a conversation, and access the attributes previously assigned to said participants when they initially joined the conversation. The problem is, when I do access as shown below, the attribute() is empty.
I have verified that said participants on the Twilio Console do indeed have attributes assigned, and they are assigned as a String Type.
Am I missing something?
I am using swift, "TwilioConversationsClient" on an iOS client.
Any Help would greatly be appreciated.
func filterParticipants() {
guard let globalConvo = globalConversation else { return }
let participants = globalConvo.participants()
for participant in participants {
let participantAttributes = participant.attributes() // Comes up Empty
let attributeDict = participantAttributes.dictionary // Comes up Empty
let attributeString = participantAttributes?.string // Comes up Empty
}
}
}
Related
So I'm working on my first workout tracking app and this is my first time using Firebase/Firestore, so I'm just trying to figure out if there is a simple query that I can use for this...
Here is what my Firestore Database structure looks like:
/Users/mi9P3TrLwkQ3oDIut/Days/WZ3Q6LDuu1kja/Workouts/BpLGFREoJNzNQW/Exercises/5vRWuHlcJHc/WeightReps/cKrB0Dpf0myEDQV0
Basically I need to return a value for numberOfRowsInSection, but the value that I need to access is the number of workouts that are associated with each day of the week, and I'm not too sure how to go about using the section parameter to iterate over each day document in my Days collection in order to access the Workouts subcollections and get the count of the documents there for each day collection. Does that make sense?
I hope that the question makes sense. Any help would be greatly appreciated!
Not entirely sure if I am getting your question right but if you want to retrieve several documents with all their attributes this is how you can do it:
var counter = 0
func getData() {
let db = Firestore.firestore()
let userID = Auth.auth().currentUser!.uid
for data in self.dataSourceArray {
db.collection("users").document(userID).collection("yourCollectionName").document(data.name).collection("yourCollectionName").getDocuments() { ( querySnapshot, error) in
if let error = error {
print(error.localizedDescription)
} else {
for document in querySnapshot!.documents {
self.counter += 1
}
}
}
}
}
Is this what youre looking for ?
First off, if you have a suggestion for a better title or actual question for this submission, please feel free to edit. I'm stuck as to how to succeed in asking this question.
So I've made gone through several Firebase chat (iMessage/ Facebook chat) tutorials for swift. I know how to send a message -
let ref = Database.database().reference().child("Message")
let childRef = ref.childByAutoId()
let toID = finalSelected.ContactID as Any
let fromID = Auth.auth().currentUser?.uid
let values = ["Message": messageTextField.text!, "toID": toID, "fromID": fromID!] as [String: Any]
childRef.updateChildValues(values) { (error, ref) in ...
and I know how to retrieve them -
let messagesOf = Auth.auth().currentUser?.uid
let messageDB = Database.database().reference().child("Message")
let userMessages = messageDB.queryOrdered(byChild: "toID").queryEqual(toValue: messagesOf)
userMessages.observeSingleEvent(of: .childAdded, with: { (snapshot) in
let values = snapshot.value as! Dictionary<String, String>
let message = values["Message"]
let from = values["fromID"]
let post = ChatMessages()
post.aMessage = message!
post.Interested = from!
self.messagesArray.append(post)
self.tableView.reloadData()
})
However, I'm having a difficult time finishing the logic. I don't understand how these two separate events combine into one identical end result - not two different transactions. Let me see if I can explain it further...
I send a message. I then receive this message as another user. But I do not understand how the to/from data is downloaded that references both simultaneously. Unless I'm looking overlooking some detail, doesn't the single or plural observation of an event only apply to one user? Or am I misunderstanding some concept here?
Help with this final concept would be fantastic. Thank You.
You now have a single list of chat messages, which is very similar to how you'd model this in a relations database. But Firebase is a NoSQL database, so you have better options for modeling chat.
The most common solution is to model chat rooms into your database. So if two users are chatting, then the messages between those two users will be in a "room node". And if two other users are also chatting, their messages will be in a separate room. The data model for this will look like:
chats: {
roomid1: {
messageid1: {
fromId: "UidOfSender1",
message: "Hello there user 2!"
},
messageid2: {
fromId: "UidOfSender2",
message: "Hey user 1. How are you?"
}
},
roomid2: {
messageid3: {
fromId: "UidOfSender2",
message: "Hi mom. Are you there?"
},
messageid4: {
fromId: "UidOfSender3",
message: "Hey there kiddo. Sup?"
}
}
}
So in here we have two chat rooms, the first one between user 1 and 2, and the second between users 2 and 3. If you think of your favorite messaging application, you can probably see how the rooms very directly map to the conversations you see.
Also note that you only need to keep the sender ID. The recipient(s) are are simply everyone else who is in this chat room.
That will likely be your next question: how do I know what rooms a user is in. To determine that, you'll want to keep a separate list of room IDs for each user:
userRooms: {
UidOfSender1: {
room1: true,
room2: true
},
UidOfSender2: {
room1: true
},
UidOfSender3: {
room2: true
}
}
So now you can see for each user in what rooms they are a participant. You can probably again see how this maps to the list of conversations when you start your favorite messaging app. To efficiently show such a list, you may want to keep some extra information for each room, such as the timestamp when the last message was posted.
Generating the room IDs is another interesting aspect of this model. In the past I've recommended to use the UIDs of the participants to determine the room ID, since that leads to a consistent, repeatable room ID. For an example if this, see http://stackoverflow.com/questions/33540479/best-way-to-manage-chat-channels-in-firebase.
If you're new to NoSQL database, I recommend reading NoSQL data modeling. If you come from a SQL background, I recommend watching Firebase for SQL developers.
var newthing = "\(CurrentChatUserId) & \(otherDude)"
Ref.child("posts").child(newthing).queryOrderedByKey().observe(.childAdded, with: {snapshot in
if let dict = snapshot.value as? [String: AnyObject]
{
let mediaType = dict["MediaType"] as! String
let senderId = dict["senderId"] as! String
let senderName = dict["senderName"] as! String
self.obsereveUsers(id: senderId)
let text = dict["text"] as! String
self.messages.append(JSQMessage(senderId: senderId, displayName: senderName , text: text))
self.collectionView.reloadData()
}
})
You could do something like this, so in the database you have different sections for each conversation and at the start get all past messages, and get new ones when a new one is added.
I'm trying to make a group chat app, and so far I have the app setup (from a tutorial) so that any user can create a room, and all of those rooms show up in a central list, which is the same for all users. Now I need to alter this so that users only see rooms that they created, or have been added to (just like any messaging app like iMessage).
This is how a room is created and appended to the Room object (and uploaded to Firebase):
var rooms: [Room] = []
// Create new room
#IBAction func createRoom(_ sender: Any) {
if let name = newRoomTextField?.text {
let newRoomRef = roomRef.childByAutoId()
let roomItem = [
"name": name
]
newRoomRef.setValue(roomItem)
}
}
private func observeRooms() {
// Observe method to listen for new channels being written to Firebase
roomRefHandle = roomRef.observe(.childAdded, with: { (snapshot) -> Void in
let roomData = snapshot.value as! Dictionary<String, AnyObject>
let id = snapshot.key
if let name = roomData["name"] as! String!, name.characters.count > 0 {
self.rooms.append(Room(id: id, name: name))
self.tableView.reloadData()
} else {
print("Error! Could not decode channel data")
}
})
}
Room object:
internal class Room {
internal let id: String
internal let name: String
init(id: String, name: String) {
self.id = id
self.name = name
}
}
Currently the table view of rooms is populated with cell.textLabel?.text = rooms[(indexPath as NSIndexPath).row].name (cellForRow method), and return rooms.count (numberOfRows method), thus returning all of the rooms in the app, not specific to the user.
This is where I'm not sure how to proceed: I'm guessing I'll add an array "participants: [String]" to my Room object (in addition to "id" and "name"), then in observeRooms when I self.rooms.append(Room(id: id, name: name)), I'll also append the user's id to "participants"? Then populate the table view with only the rooms that the current user's id is a participant in?
Is this the right approach?
Thanks for any help/guidance!
I think this is the right approach, you basically have 2 choices :
Store a participants array into each room, which allow you to query rooms where this array contains our current userId.
Store a rooms array on each user, allowing to query rooms directly from this data.
The first approach seems to make more sense in case you'd like to also display a list of participants, though the query may take longer to execute than the second approach for many rooms * many participants.
You could also use both approach at the same time to have both your functionality and a faster query time for the user rooms.
So I am currently working on a clone like snapchat and I am sending pull requests to the server, but as for downloading, it is not going so well. I created a reference to the database that looks like this,
var recievers: FIRDatabaseReference{
return mainRef.child("pullRequests")
}
and then I have a viewController that parses the data (which I know isn't the best way to go about this but I'm just trying to get it working right now) and in there I have this
DataService.instance.recievers.observeSingleEvent(of: .value) {(recipients: FIRDataSnapshot) in
if let recipient = recipients.value as? Dictionary<String,AnyObject>{
var index = 0;
for(key,value) in recipient{
index = index+1
if let dict = value as? Dictionary<String,AnyObject>{
if let reciever = dict["recipents"] as? Dictionary<String,AnyObject>{
if let num = reciever["\(index)"] as? String{
let uid = num
recipientsArr.append(uid)
}
}
}
}
}
}
for i in 0...recipientsArr.count{
print(i)
}
I'm not getting any compiling errors but it is also not adding anything into the recipientsArr, can anyone help guide me in the right direction?
My Firebase looks like this:
You're not decoding the snapshot properly. Its unclear from your question what is the value event you want to observe - is it just a new recipient that was added? the whole pullRequest?
In any case you're observing the pullRequest reference and therefore in order to decode the snapshot:
if let pullRequest = recipients.value as? Dictionary<String,AnyObject>{
if let recipientsList = pullRequest["recipents"] as? Dictionary<String,AnyObject>{
for (_, value) in recipientsList {
if let uid = value as? String{
recipientsArr.append(uid)
}
}
}
}
The problem is that you are using the method observeSingleEvent to update the value in the database, when this method is only used to recieve data from the database, not updated. In other words, it read-only.
The way to update record in a firebase database works different than the read methods. You can use both methods setValue and updateChildValues to perform updates. They both work on a database reference.
To use the setValue method, you should do something like this. I'll assume that you already have a pullRequests object that you previously created from the information you fetched from the database and have it in a variable:
let previousRecipents = pullRequests.recipents
let allRecipents = previousRecipents.append(newRecipent) // Assuming preivousRecipents is an array and you have the new Recipent
recievers.child("recipents").setValue(allRecipents)
To use the updateChildValues, it works very similar.
let previousRecipents = pullRequests.recipents
let allRecipents = previousRecipents.append(newRecipent) // Assuming preivousRecipents is an array and you have the new Recipent
let parametersToUpdate = ["recipents": allRecipents]
recievers.updateChildValues(parametersToUpdate)
For further information on how to update, check the following link:
https://firebase.google.com/docs/database/ios/save-data
Hope it helps!
I saw some post related to this topic but nothing comes handy for me in this case. I am using Magical Records for storing data. Data is saving fine for the first time as I map it after coming from server.
class func fnsConversationmapper(conversationJson: [JSON]) -> [Conversation] {
var conversationArray = [Conversation]()
for conversationDict in conversationJson {
print(conversationDict)
// let check = Conversation.mr_find(byAttribute: "id", withValue: conversationDict["id"].stringValue)
let check = Conversation.mr_findFirst(byAttribute: "id", withValue: conversationDict["id"].stringValue)
let conversationObj = Conversation.mr_createEntity()
conversationObj?.name = conversationDict["name"].stringValue
conversationObj?.id = conversationDict["id"].stringValue
conversationObj?.image = conversationDict["avatar"].stringValue
conversationObj?.type = conversationDict["type"].stringValue
conversationObj?.role = conversationDict["postedBy"]["role"]["name"].stringValue
conversationObj?.postedOn = (conversationDict["postedOn"].stringValue).dateFromString() as NSDate?
conversationArray.append(conversationObj!)
if check == nil {
NSManagedObjectContext.mr_default().mr_saveToPersistentStoreAndWait()
}
print("Saved data", Conversation.mr_findAll()!)
}
return conversationArray
}
I also have a check to see if the record is already present in db, but somehow when I again run the app from certain scenario (coming back and forth from some screens), entries get doubled in db. I am not understanding how this is happening. Any Help will be appreciated.
Thanks.