9

Tôi sẽ xem tài liệu và hướng dẫn của Firestore. Mẫu mã của tôi dưới đây sử dụng AngularFire2.Cách tốt nhất để lấy dữ liệu từ các bộ sưu tập được lồng trong tài liệu trong Firestore là gì?

Hãy xem xét một "chat" bộ sưu tập tương tự như các ví dụ được cung cấp ở đây: https://firebase.google.com/docs/firestore/manage-data/structure-data

Họ khuyên loại cấu trúc này nhưng tôi không thấy nơi họ thảo luận nhận được tất cả các dữ liệu một cách hiệu quả.

Mỗi tài liệu trò chuyện có tính chất, một bộ sưu tập của các thành viên, và một tập hợp các thông điệp:

  • chatsCollection
    • chatDocument
      • [chèn lĩnh vực trò chuyện dữ liệu ở đây]
      • membersCollection
        • memberDocument
          • [chèn trường dữ liệu thành viên tại đây]
      • messagesCollection
        • messageDocument
          • [chèn trường dữ liệu lời nhắn ở đây]

truy vấn FireStore là nông cạn, mà có thể là tuyệt vời đôi khi. Sự hiểu biết của tôi là không có cách nào để truy vấn sâu và nhận các bộ sưu tập lồng nhau. Vì vậy, các phương pháp hay nhất và cách rắc rối nhất để làm điều này là gì?

Hiện tại tôi đang truy xuất và ánh xạ các ảnh chụp nhanh đến các đối tượng có ID và thêm dữ liệu lồng nhau vào dữ liệu tài liệu gốc với các truy vấn và ánh xạ bổ sung và tôi không hài lòng với cách tiếp cận của mình. ngay cả với cấu trúc Firebase không chuẩn hóa.

Mã này ví dụ chỉ là lập bản đồ trên các thành viên, cộng lại trong các tin nhắn là một câu chuyện hoàn toàn khác ...

getChatsFromFirestore() { 
    this.chats = this.dataSvc.getChatsFromFirestore().snapshotChanges() 
     .map(chatSnaps => { 
     return chatSnaps.map(chat => { 
      const chatData = chat.payload.doc.data(); 
      const chatId = chat.payload.doc.id; 
      return this.dataSvc.getMembersForChat(chatId) 
      .snapshotChanges() 
      .map(memberSnaps => { 
       return memberSnaps.map(member => { 
       const data = member.payload.doc.data(); 
       const id = member.payload.doc.id; 
       return { id, ...data } 
       }); 
      }) 
      .map(members => { 
       return { chatId, ...chatData, members: members }; 
      }); 
     }) 
     }) 
     .flatMap(chats => Observable.combineLatest(chats)); 
    } 

Và từ dịch vụ:

getChatsFromFirestore() { 
    return this.fsd.collection<any>('chats'); 
} 
getChatFromFirestoreById(id: string) { 
    return this.fsd.doc(`chats/${id}`); 
} 
getMembersForChat(chatId) { 
    return this.getChatFromFirestoreById(chatId).collection('members'); 
} 
+1

Tôi đoán có một cuộc tranh cãi vào đây để sao chép & denormalizing dữ liệu theo quá trình cho cơ sở dữ liệu thời gian thực (một cái gì đó như [câu trả lời này ] (https://stackoverflow.com/a/30699277/2754146)), nhưng tôi cũng hy vọng có một quy trình khác nhau/tốt hơn để tham gia dữ liệu trong Firestore. – Grimthorr

+1

Điểm tốt và tôi đã làm lệch và làm mất dữ liệu một chút trong trường hợp này. Ví dụ: mỗi cuộc trò chuyện chứa các thành viên có ID tài liệu phù hợp với UID có thể được sử dụng để lấy tất cả dữ liệu của thành viên đó, nhưng cũng chứa tên của người dùng. Mỗi thư cá nhân cũng chứa trường "authorName" và trường "sentBy" giữ UID của người dùng đó một lần nữa ... vẫn có thể nhận tất cả dữ liệu lồng nhau trong tài liệu phòng chat mà không có cuộc gọi đệ quy đến DB hoặc ít nhất với ít chi tiết hơn mã sẽ được mát mẻ. – Methodician

+0

Nếu bạn lưu id với 'chatDocument' làm trường, bạn có thể sử dụng' .valueChanges() 'và lấy id. nhanh hơn '.snapshotChanges()'. – Hareesh

Trả lời

0

Cách tiếp cận bạn đăng dường như giống như nó sẽ hoạt động và cho một ứng dụng trò chuyện lớn, bạn có thể không muốn theo dõi mọi sự kiện xảy ra trong mỗi phòng chat vì có thể có rất nhiều dữ liệu.Thay vào đó, có lẽ sẽ tốt hơn nếu bạn chỉ đăng ký với những gì cần thiết và xử lý các cập nhật định kỳ với các chức năng đám mây và tin nhắn trên đám mây.

Bằng cách sử dụng chức năng trợ giúp observeCollection cũng như chuyển đổi mã nhỏ, nó sẽ dọn dẹp dịch vụ và tạo các quan sát cho mỗi phòng chat sẽ không hoạt động cho đến khi chúng được đăng ký.

class Service { 
    // db is plan firestore/no angularfire 
    db: firebase.firestore.Firestore; 

    loadChatrooms() { 
     const chatsRef = this.db.collection('chats'); 
     return observeCollection(chatsRef) 
      .pipe(
       map(chats => { 
        return chats.map(chat => { 
         return { 
          chat, 
          members$: this.observeCollection(chat.ref.collection('members')), 
          messages$: this.observeCollection(chat.ref.collection('messages')), 
         }; 
        }) 
       }), 
      ); 
    } 

    // Takes a reference and returns an array of documents 
    // with the id and reference 
    private observeCollection(ref) { 
     return Observable.create((observer) => { 
      const unsubscribeFn = ref.onSnapshot(
       snapshot => { 
        observer.next(snapshot.docs.map(doc => { 
         const data = doc.data(); 
         return { 
          ...doc.data(), 
          id: doc.id, 
          ref: doc.ref 
         }; 
        })); 
       }, 
       error => observer.error(error), 
      ); 

      return unsubscribeFn; 
     }); 
    } 
} 

Trong ứng dụng, bạn chỉ có thể quan sát các thành viên và tin nhắn trò chuyện hiện đang được chọn để lưu dữ liệu. Vì bài đăng này được gắn thẻ với các ống async góc sẽ giúp chuyển đổi bằng các trình con trỏ tự động.

Trong thành phần của bạn:

this.currentChat$ = combineLatest(
    service.loadChatrooms(), 
    currentlySelectedRoomId 
).pipe(
    map(([chats, selectedRoomId]) => { 
     return chats.first(chat => chat.id === selectedRoomId) 
    }) 
); 

Trong mẫu của bạn:

<div *ngIf="currentChat$ as currentChat"> 
    {{ currentChat.name }} 

    <div *ngIf="currentChat.members$ as members"> 
     <div *ngIf="let member of members"> 
      {{ member.name }} 
     </div> 
    </div> 

    <div *ngIf="currentChat.messages$ as messages"> 
     <div *ngIf="let message of messages"> 
      {{ message.content }} 
     </div> 
    </div> 
</div> 
+0

Vui lòng thảo luận thêm nếu câu trả lời được đi đúng hướng. – adamduren

Các vấn đề liên quan