in Education by
I'm relatively new to Swift and Firebase, so I'm not very familiar with the intricacies of how both work together. I'm building a chat app that has messages and threads. A user can send a message, struct Message, and if another user wants to directly reply to that message, a thread is created. For each message, I'm storing an array of Firebase document references to the other messages in the thread, threadBefore: [Message]. struct Message: Codable, Identifiable { var id: String var content: String var name: String var upvotes: Int var likedByUser: Bool var dontShow: Bool var sentAt: Date var threadsArray: [Message] } The following is my code for fetching all the chat messages from Firebase: dontShow property: if dontShow == true means that the message is inside the thread and shouldn't be displayed like a regular message in the chat. However, the very last message in the thread is displayed and has dontShow = false. func fetchMessages(docId: String, collectionType: String, isThreadMember: Bool) { if (user != nil) { db.collection("chatrooms").document(docId).collection(collectionType).order(by: "sentAt", descending: false).addSnapshotListener { (snapshot, error) in guard let documents = snapshot?.documents else { print("No messages") return } // let threadsTemp: [Message]() let classroomId = docId if !isThreadMember { if collectionType == "messages" { self.messages = documents.map { doc -> Message in let data = doc.data() let docId1 = doc.documentID let content = data["content"] as? String ?? "" let displayName = data["displayName"] as? String ?? "" let likedUsersArr = data["likedUsers"] as? Array ?? [""] // if message is in thread (but not last message), then don't show as normal message, but in thread let dontShow = data["dontShow"] as? Bool ?? false let sentAt = data["sentAt"] as? Date ?? Date() let threadBefore = data["threadBefore"] as? [DocumentReference] ?? [DocumentReference]() // using reference array if dontShow == false { if (threadBefore.count > 0) { // reset the temporary array that holds the threads to be added afterwards self.threadsTemp = [] for docRef in threadBefore { docRef.getDocument { (doc2, error) in if let doc2 = doc2, doc2.exists { let docId2 = doc2.documentID self.fetchThreadMessages(classroomId: classroomId, parentMessageId: docId1, docId: docId2) } else { print("Document does not exist") } } } } } return Message(id: docId1, content: content, name: displayName, upvotes: likedUsersArr.count, likedByUser: likedUsersArr.contains(self.user!.uid) ? true : false, dontShow: dontShow, sentAt: sentAt, threadsArray: self.threadsTemp) } } Another function: fetchThreadMessages: // fetch a specified message and then append to the temporary threads array, threadsTemp func fetchThreadMessages(classroomId: String, parentMessageId: String, docId: String) -> Message { if (user != nil) { let docRef = db.collection("chatrooms").document(classroomId).collection("messages").document(docId) docRef.getDocument { (doc, error) in if let doc = doc, doc.exists { if let data = doc.data(){ let docId = doc.documentID print("docid") print(docId) let content = data["content"] as? String ?? "" let displayName = data["displayName"] as? String ?? "" let likedUsersArr = data["likedUsers"] as? Array ?? [""] // if message is in thread (but not last message), then don't show as normal message, but in thread let dontShow = data["dontShow"] as? Bool ?? false let sentAt = data["sentAt"] as? Date ?? Date() self.threadsTemp.append(Message(id: docId, content: content, name: displayName, upvotes: likedUsersArr.count, likedByUser: likedUsersArr.contains(self.user!.uid) ? true : false, dontShow: true, sentAt: sentAt, threadsArray: [])) } } } } } I haven't implemented how the sendMessage() function updates the threadBefore array, but I'm currently updating this field directly on Firebase just for testing. func sendMessage(messageContent: String, docId: String, collectionType: String, isReply: Bool, threadId: String) { if (user != nil) { if isReply { let docRef = db.collection("chatrooms").document(docId).collection(collectionType).document(threadId) self.threadRef = db.document(docRef.path) } db.collection("chatrooms").document(docId).collection(collectionType).addDocument(data: [ "sentAt": Date(), "displayName": user!.email ?? "", "content": messageContent, "likedUsers": [String](), "sender": user!.uid, "threadBefore": isReply ? [threadRef] : [DocumentReference](), "dontShow": false]) } } A little bit more on how I'm fetching and retrieving the document references from threadsBefore: For each message in the collection, I loop its threadsArray, which consists of DocumentReferences to other messesages that are in that thread. For each of those document references, I run self.fetchThreadMessages. This retrieves that message and stores a Message() instance in threadsTemp. Then, back in self.fetchMessage, when I'm done filling up the self.threadsTemp with all of the documents retrieved from threadsBefore, I store it in threadsArray property in the Message struct. Now, look at the return state in self.fetchMessages above, the very last assignment inside Message() is threadsArray: self.threadsTemp. But the problem here is that this is just a reference? And it would change based on the last assignment to self.threadsTemp? I've tried multiple ways to implement this entire storing and retrieving thing. But all came with several complicated errors. I tried using dictionaries, or storing just the document id's for the thread messages and then look them up in self.Messages (since it has all of the messages stored in it). What's the best way to implement this? Or fix my errors? I know my code is probably a mishmash of inefficient and confused coding practices. But I'm trying to learn. JavaScript questions and answers, JavaScript questions pdf, JavaScript question bank, JavaScript questions and answers pdf, mcq on JavaScript pdf, JavaScript questions and solutions, JavaScript mcq Test , Interview JavaScript questions, JavaScript Questions for Interview, JavaScript MCQ (Multiple Choice Questions)

1 Answer

0 votes
by
With that being said (meaning, my comment above), I'm going to not as much address your code as I am going to propose what I think is a good way to organize your Firestore database for a chat app. Then, hopefully you will be able to apply it to your own situation. First things first, we have to remember that Firestore charges based on the number of queries you make - it does not take into account the amount of data that is being fetched in a particular query - so fetching a single word is as expensive as fetching an entire novel. As such, we should structure our database in a way that is financially efficient. What I would do personally is structure my database with two primary sections, (1) conversation threads and (2) users. Each user contains references to their threads they are a part of, and each thread contains a reference to the users that are in that thread. That way we can easily and efficiently fetch a user's conversations, or obtain the users in a particular conversation. // COL = Collection // DOC = Document Threads (COL) Thread1 (DOC) id: String // id of the thread participants: [String: String] = [ user1: [ "username": "Bob23", "userID": IJ238KD... // the document id of the user ] ] // Keep this "participants" dictionary in the root of the thread // document so we have easy access to fetch any user we want, if // we so desire (like if the user clicks to view the profile of a // user in the chat. Messages (COL) Message1 (DOC) from: String // id of user that sent message Message2 (DOC) ... ... Thread 2 (DOC) ... ... Users (COL) User1 (DOC) threadIDs: [String] // Contains the thread "id"s of all the threads // the user is a part of. (You probably want to // use a dictionary instead since array's can be // difficult to work with in a database, but for // simplicity, I'm going to use an array here.) User2 (DOC) ... ... Now, let's say the user opens the app and we need to fetch their conversation threads. It's as easy as db.collection("Threads").whereField("id", in: user.threadIDs) [EDIT] user.threads would be a local array of type String. You should have this data on hand since you would be fetching the current user's User document on app launch, which is why we include this data in that user document. Basically, this query returns every document in the Threads collection whose "id" field exists in the array of the user's threadIDs (which is an array of type String). You can read more about Firestore queries in their docs here. In other words, we get every thread document that the user has references to. The great thing about this is that it takes only one query to return all of the conversations of a user. Now let's say the user is scrolling through their conversation threads in the app, and they tap one of them to open up the messages. Now, all we do is fetch all the messages in that particular thread, again only requiring one query to do so. Last but not least, if for some reason we have to get info about a particular user in a conversation, we have all the references we need within that thread document itself to fetch the user data, if needed.

Related questions

0 votes
    The syntax for retrieving specific elements from an XML document is ______________. (1)XMLSchema (2)XQuery (3)XPath...
asked Apr 23, 2021 in Technology by JackTerrance
0 votes
    The syntax for retrieving specific elements from an XML document is __________. (1)XML Schema (2)XQuery (3)XPath...
asked Apr 22, 2021 in Technology by JackTerrance
0 votes
    Q.17 Writing, editing, storing, and printing a document using computer software, are known as * O Word ... O Excel Powerpoint Select the correct answer from above options...
asked Dec 23, 2021 in Education by JackTerrance
0 votes
    this is my first question here, i hope you can help me. I've been trying to get a specific path ... , JavaScript Questions for Interview, JavaScript MCQ (Multiple Choice Questions)...
asked Apr 16, 2022 in Education by JackTerrance
0 votes
    this is my first question here, i hope you can help me. I've been trying to get a specific path ... , JavaScript Questions for Interview, JavaScript MCQ (Multiple Choice Questions)...
asked Apr 16, 2022 in Education by JackTerrance
0 votes
    When you start the application, you should get a line from the Firestore documents and write to an array, ... Questions for Interview, JavaScript MCQ (Multiple Choice Questions)...
asked Apr 16, 2022 in Education by JackTerrance
0 votes
    I am developing an addon for Gmail using AppsScript. One of the use cases of my addon is to retrieve ... .getAttachments() API which returns only the gmail attachments (...
asked May 4, 2022 in Education by JackTerrance
0 votes
    I'm having trouble with understanding how to properly do unwrapping in Swift. Here is the situation: I have ... Questions for Interview, JavaScript MCQ (Multiple Choice Questions)...
asked May 7, 2022 in Education by JackTerrance
0 votes
    How do I see which version of Swift I'm using?...
asked Mar 9, 2021 in Technology by JackTerrance
0 votes
    What is a GUARD statement? What is the benefit of using the GUARD statement in swift?...
asked Nov 30, 2020 in Technology by JackTerrance
0 votes
    What are the advantages of using Swift?...
asked Nov 30, 2020 in Technology by JackTerrance
0 votes
    On my website I am trying to program a feature, similar to facebook and twitters timeline, where a user ... Questions for Interview, JavaScript MCQ (Multiple Choice Questions)...
asked Mar 3, 2022 in Education by JackTerrance
0 votes
    On my website I am trying to program a feature, similar to facebook and twitters timeline, where a user ... Questions for Interview, JavaScript MCQ (Multiple Choice Questions)...
asked Mar 2, 2022 in Education by JackTerrance
0 votes
    Which is the next step after retrieving the content in chunks? (a) Paint DOM elements (b) Parse ... JavaScript Questions for Interview, JavaScript MCQ (Multiple Choice Questions)...
asked Oct 23, 2021 in Education by JackTerrance
0 votes
    In order to reduce the overhead in retrieving the records from the storage space we use (a) Logs ( ... Answers, Database Interview Questions and Answers for Freshers and Experience...
asked Oct 11, 2021 in Education by JackTerrance
...