ahmet varli
ahmet varli

Reputation: 1

"FIRESTORE : Invalid document reference. Document references must have an even number of segments, but chats/GP6sgTdilUZql2XvZUxQhQLimhm1/chats has 3"

This is my second app. when l was try to send message l get this error :

Thread 1: "FIRESTORE INTERNAL ASSERTION FAILED: Invalid document reference. Document references must have an even number of segments, but chats/GP6sgTdilUZql2XvZUxQhQLimhm1/chats has 3"

this is my chat service


class ChatService: ObservableObject {
    @Published var isLoading = false
    @Published var chats: [Chat] = []
    
    var listener: ListenerRegistration!
    var recipientId = ""
    
    static var chats = AuthService.storeRoot.collection("chats")
    static var messages = AuthService.storeRoot.collection("messages")
    
    static func conversation(sender: String, recipient: String) ->
        CollectionReference {
         return chats.document(sender).collection("chats").document(recipient).collection("conversation")
            
        }
    
    static func userMessages(userid: String) -> CollectionReference {
        return messages.document(userid).collection("messages")
    }
    
    static func messagesId(senderId: String, recipientId: String) ->
        DocumentReference {
            return messages.document(senderId).collection("messages").document(recipientId)
    }
    
    func loadChats() {
        self.chats = []
        self.isLoading = true
        
        self.getChats(userId: recipientId, onSuccess: {
            (chats) in
            
            if self.chats.isEmpty {
                self.chats = chats
            }
        }, onError: {
            (err) in
            print("Error \(err)")
        }, newChat: {
            (chat) in
            if !self.chats.isEmpty {
                self.chats.append(chat)
            }
        }) {
            (listener) in
            self.listener = listener
        }
    }
    
    
    func sendMessage(message: String, recipientId: String,
         recipientProfile: String, recipientName: String, onSuccess:
         @escaping()-> Void, onError: @escaping(_ error: String)-> Void) {
        
        guard let senderId = Auth.auth().currentUser?.uid else {return}
        guard let senderUsername = Auth.auth().currentUser?.displayName
            else {return}
        
        guard let senderProfile = Auth.auth().currentUser?.photoURL!.absoluteString else {return}
                                        
        let messageId = ChatService.conversation(sender: senderId,
            recipient: recipientId).document().documentID
        
        let chat = Chat(messageId: messageId, textMessage: message,
            profile: senderProfile, photoUrl: "", sender: senderId,
            username: senderUsername, timestamp:
            Date().timeIntervalSince1970, isPhoto: false)
        
        guard let dict = try? chat.asDictionary() else {return}
        
        ChatService.conversation(sender: senderId, recipient:
            recipientId).document(messageId).setData(dict) {
            (error) in
            
            if error == nil {
                ChatService.conversation(sender: recipientId, recipient:
                    senderId).document(messageId).setData(dict)
                
                let senderMessage = Message(lastMessage: message,
                    username: senderUsername, isPhoto: false,
                    timestamp: Date().timeIntervalSince1970, userId:
                    senderId, profile: senderProfile)
                
                let recipientMessage = Message(lastMessage: message,
                    username: recipientName, isPhoto: false,
                    timestamp: Date().timeIntervalSince1970, userId:
                    recipientId, profile: recipientProfile)
                
                    guard let senderDict = try? senderMessage.asDictionary()
                        else {return}
                
                    guard let recipientDict = try? recipientMessage.asDictionary()
                        else {return}
                
                ChatService.messagesId(senderId: senderId, recipientId: recipientId).setData(senderDict)
                
                ChatService.messagesId(senderId: recipientId, recipientId: senderId).setData(recipientDict)
                
                onSuccess()
            } else {
                onError(error!.localizedDescription)
            }
        }
    }
      
    func sendPhotoMessage(imageData: Data, recipientId: String,
         recipientProfile: String, recipientName: String, onSuccess:
         @escaping()-> Void, onError: @escaping(_ error: String)-> Void) {
        
        guard let senderId = Auth.auth().currentUser?.uid else {return}
        guard let senderUsername = Auth.auth().currentUser?.displayName
            else {return}
        
        guard let senderProfile = Auth.auth().currentUser?.photoURL!.absoluteString else {return}
        
        let messageId = ChatService.conversation(sender: senderId,
            recipient: recipientId).document().documentID
        
       let storageChatRef = StorageService.storagechatId(chatId: messageId)
        
        let metadata = StorageMetadata()
        metadata.contentType = "image/jpg"
      
      StorageService.saveChatPhoto(messageId: messageId, recipientId:
            recipientId, recipientProfile: recipientProfile,
            recipientName: recipientName, senderProfile: senderProfile,
            senderId: senderId, senderUsername: senderUsername, imageData:
            imageData, metadata: metadata, storageChatRef: storageChatRef,
            onSuccess: onSuccess, onError: onError) 
       }
    
    
    
    func getChats(userId: String, onSuccess: @escaping([Chat])->
         Void, onError: @escaping(_ error: String)-> Void, newChat:
         @escaping(Chat)-> Void, listener: @escaping(_ listenerHandle:
         ListenerRegistration)-> Void) {
        
        let listenerChat = ChatService.conversation(sender:
            Auth.auth().currentUser!.uid, recipient:
            userId).order(by: "timestamp", descending:
            false).addSnapshotListener {
            (qs, err) in
                
                guard let snapshot = qs else {
                    return
            }
                
             var chats = [Chat]()
                
                snapshot.documentChanges.forEach {
                    (diff) in
                    
                    if(diff.type == .added) {
                        let dict = diff.document.data()
                        
                        guard let decoded = try? Chat.init(fromDictionary: dict) else {
                            return
                    }
                   newChat(decoded)
                   chats.append(decoded)
                   }
                    if(diff.type == .modified) {
                        print("modified")
                   }
                    if(diff.type == .removed) {
                        print("removed")
                    }
                       
              }
                onSuccess(chats)
            }
             listener(listenerChat)
      }
      
    func getMessages(onSuccess: @escaping([Message])-> Void, onError:
         @escaping(_ error: String)-> Void, newMessage: @escaping(Message)->
         Void, listener: @escaping(_ listenerHandle:
         ListenerRegistration)-> Void) {
        
        let listenerMessage = ChatService.userMessages(userid:
            Auth.auth().currentUser!.uid).order(by: "timestamp",
            descending: true).addSnapshotListener {
            (qs, err) in
                
            guard let snapshot = qs else {
                return
            }
                
            var messages = [Message]()
                snapshot.documentChanges.forEach {
                    (diff) in
                    
                    if(diff.type == .added) {
                        let dict = diff.document.data()
                        
                    guard let decoded = try? Message.init(fromDictionary:
                        dict) else {
                        return
                    }
                      newMessage(decoded)
                      messages.append(decoded)
                   }
                    if(diff.type == .modified) {
                        print("modified")
                   }
                    if(diff.type == .removed) {
                        print("removed")
            }
        }
            onSuccess(messages)
    }
         listener(listenerMessage)
  }

}

debug showed me this line and this reference



 static func conversation(sender: String, recipient: String) ->
        CollectionReference {
         return chats.document(sender).collection("chats").document(recipient).collection("conversation")
                                                           ^Thread^ 
        }

The guy l watch to tutoriol is dead befor the finish.and I don't fully understand my mistake.

Upvotes: 0

Views: 1665

Answers (1)

slushy
slushy

Reputation: 12375

chats/GP6sgTdilUZql2XvZUxQhQLimhm1/chats points to a collection:

  • collection: chats (segment 1)
    • document: GP6sgTdilUZql2XvZUxQhQLimhm1 (segment 2)
      • subcollection: chats (segment 3)

And so chats/GP6sgTdilUZql2XvZUxQhQLimhm1 points to a document. Therefore, adjust accordingly. Remember, a document must start in a collection and a document can't contain a document and a collection can't contain a collection, they must alternate.

Upvotes: 2

Related Questions