Bộ sưu tập con truy vấn Firestore


125

Tôi nghĩ rằng tôi đã đọc rằng bạn có thể truy vấn các bộ sưu tập con bằng Firebase Firestore mới, nhưng tôi không thấy bất kỳ ví dụ nào. Ví dụ: tôi đã thiết lập Firestore của mình theo cách sau:

  • Dances [bộ sưu tập]
    • danceName
    • Bài hát [bộ sưu tập]
      • tên bài hát

Làm cách nào để tôi có thể truy vấn "Tìm tất cả các điệu nhảy trong songName == 'X'"


1
cửa hàng cứu hỏa này có được hỗ trợ chưa, năm 2020 không?
sajanyamaha

Câu trả lời:


148

Cập nhật 2019-05-07

Hôm nay, chúng tôi đã phát hành các truy vấn nhóm bộ sưu tập và những truy vấn này cho phép bạn truy vấn trên các bộ sưu tập con.

Vì vậy, ví dụ trong SDK web:

db.collectionGroup('Songs')
  .where('songName', '==', 'X')
  .get()

Điều này sẽ khớp với các tài liệu trong bất kỳ bộ sưu tập nào có phần cuối cùng của đường dẫn bộ sưu tập là 'Bài hát'.

Câu hỏi ban đầu của bạn là về việc tìm các điệu nhảy ở nơi songName == 'X' và điều này vẫn không thể thực hiện trực tiếp, tuy nhiên, đối với mỗi Bài hát phù hợp, bạn có thể tải bài hát gốc của nó.

Câu trả lời ban đầu

Đây là một tính năng chưa tồn tại. Nó được gọi là "truy vấn nhóm sưu tập" và cho phép bạn truy vấn tất cả các bài hát bất kể điệu nhảy nào chứa chúng. Đây là điều mà chúng tôi dự định sẽ hỗ trợ nhưng không có lịch trình cụ thể về thời điểm nó đến.

Cấu trúc thay thế ở thời điểm này là biến các bài hát thành một bộ sưu tập cấp cao nhất và biến điệu nhảy của bài hát đó là một phần thuộc tính của bài hát.


147
Sẽ tốt hơn RẤT NHIỀU nếu nhóm phát triển Firestore triển khai các truy vấn bộ sưu tập con càng sớm càng tốt. Xét cho cùng, 'truy vấn mạnh mẽ hơn' là một trong những điểm hấp dẫn chính theo hướng dẫn sử dụng Firestore. Hiện tại, Firestore giống như một chiếc Porsche không có bánh xe.
Arne Wolframm

21
Chúng ta đồng ý! Chỉ có một số giờ giới hạn trong ngày :-).
Gil Gilbert

20
Tôi không hiểu, mọi người trả tiền để làm gì, nếu firebase có giới hạn? Có vẻ như ngay cả Backendless cũng có nhiều chức năng hơn Firebase. Và tại sao Firebase lại phổ biến như vậy? Dường như mọi người đã điên
nzackoya

15
Tính năng này rất cần thiết nếu không mọi người sẽ bắt đầu tìm các giải pháp thay thế, ngay cả khi chúng tôi có thời hạn để đáp ứng. : P
JD-V

13
Chúng tôi cần tính năng này. Tại thời điểm cho thuê dòng thời gian để phát hành điều này sẽ giúp chúng tôi chuẩn bị.
sanjaya panigrahy

22

CẬP NHẬT Hiện Firestore hỗ trợ mảng chứa

Có những tài liệu này

    {danceName: 'Danca name 1', songName: ['Title1','Title2']}
    {danceName: 'Danca name 2', songName: ['Title3']}

làm như thế này

collection("Dances")
    .where("songName", "array-contains", "Title1")
    .get()...

@ Nelson.b.austin Vì firestore chưa có, tôi khuyên bạn nên có một cấu trúc phẳng, nghĩa là:

Dances = {
    danceName: 'Dance name 1',
    songName_Title1: true,
    songName_Title2: true,
    songName_Title3: false
}

Có nó theo cách đó, bạn có thể hoàn thành nó:

var songTitle = 'Title1';
var dances = db.collection("Dances");
var query = dances.where("songName_"+songTitle, "==", true);

Tôi hi vọng cái này giúp được.


2
cái gì songName_Title3: falsehữu ích cho? nếu tôi không sai, nó chỉ có thể được sử dụng để tìm kiếm các điệu nhảy không có tên bài hát cụ thể, giả sử rằng chúng tôi cần một songName_Title3: falseđể dances.where("songName_"+songTitle, "==", false); trả về kết quả như vậy, nó sẽ không khiến mọi điệu nhảy có cờ boolean cho mọi bài hát có thể tên ...
epeleg

Điều này thật tuyệt nhưng tài liệu bị giới hạn ở 1MB, vì vậy nếu bạn cần liên kết một danh sách dài các chuỗi hoặc bất cứ thứ gì với một tài liệu cụ thể, thì bạn không thể sử dụng phương pháp này.
Supertecnoboff

@Supertecnoboff Có vẻ như nó sẽ phải là một danh sách các chuỗi dài và lớn. Truy vấn "array_contains" này có hiệu suất như thế nào và các lựa chọn thay thế hiệu quả hơn là gì?
Jay Ordway

14

Điều gì sẽ xảy ra nếu bạn lưu trữ các bài hát dưới dạng một đối tượng thay vì dưới dạng một bộ sưu tập? Mỗi điệu nhảy, với các bài hát là một trường: nhập Đối tượng (không phải bộ sưu tập)

{
  danceName: "My Dance",
  songs: {
    "aNameOfASong": true,
    "aNameOfAnotherSong": true,
  }
}

thì bạn có thể truy vấn tất cả các điệu nhảy với aNameOfASong:

db.collection('Dances')
  .where('songs.aNameOfASong', '==', true)
  .get()
  .then(function(querySnapshot) {
    querySnapshot.forEach(function(doc) {
      console.log(doc.id, " => ", doc.data());
    });
   })
   .catch(function(error) {
     console.log("Error getting documents: ", error);
    });

3
Giải pháp này sẽ hoạt động nhưng nó không thể mở rộng trong trường hợp số lượng bài hát lớn hoặc có thể phát triển động. Điều này sẽ làm tăng kích thước tài liệu và ảnh hưởng đến hiệu suất đọc / ghi. Bạn có thể tìm thêm thông tin về điều này trong tài liệu Firebase được liên kết bên dưới (xem phần cuối cùng 'Hạn chế' trên trang) firebase.google.com/docs/firestore/solutions/arrays
Nouman Hanif

14

CẬP NHẬT 2019

Firestore đã phát hành Truy vấn Nhóm Bộ sưu tập. Xem câu trả lời của Gil ở trên hoặc Tài liệu chính thức về Truy vấn Nhóm Bộ sưu tập


Câu trả lời trước

Như đã nói bởi Gil Gilbert, có vẻ như các truy vấn nhóm thu thập hiện đang được thực hiện. Trong thời gian này, có lẽ tốt hơn là sử dụng các bộ sưu tập cấp gốc và chỉ cần liên kết giữa các bộ sưu tập này bằng cách sử dụng UID của tài liệu.

Đối với những người chưa biết, Jeff Delaney có một số hướng dẫn và tài nguyên đáng kinh ngạc cho bất kỳ ai làm việc với Firebase (và Angular) trên AngularFirebase .

Mô hình hóa dữ liệu quan hệ Firestore NoSQL - Ở đây anh ấy chia nhỏ những điều cơ bản về cấu trúc NoSQL và Firestore DB

Mô hình hóa dữ liệu nâng cao với Firestore bằng ví dụ - Đây là những kỹ thuật nâng cao hơn cần ghi nhớ trong tâm trí của bạn. Một bài đọc tuyệt vời cho những ai muốn nâng các kỹ năng Firestore của mình lên một tầm cao mới


7

CẬP NHẬT MỚI ngày 8 tháng 7 năm 2019:

db.collectionGroup('Songs')
  .where('songName', isEqualTo:'X')
  .get()

3

Bạn luôn có thể tìm kiếm như sau: -

this.key$ = new BehaviorSubject(null);

return this.key$.switchMap(key =>
  this.angFirestore
    .collection("dances").doc("danceName").collections("songs", ref =>
      ref
        .where("songName", "==", X)
    )
    .snapshotChanges()
    .map(actions => {
      if (actions.toString()) {
        return actions.map(a => {
          const data = a.payload.doc.data() as Dance;
          const id = a.payload.doc.id;
          return { id, ...data };
        });
      } else {
        return false;
      }
    })
);

3

Giới hạn truy vấn

Cloud Firestore không hỗ trợ các loại truy vấn sau:

  1. Truy vấn với bộ lọc phạm vi trên các trường khác nhau.

  2. Các truy vấn đơn trên nhiều bộ sưu tập hoặc bộ sưu tập con. Mỗi truy vấn chạy dựa trên một tập hợp tài liệu. Để biết thêm thông tin về cách cấu trúc dữ liệu ảnh hưởng đến các truy vấn của bạn, hãy xem Chọn cấu trúc dữ liệu .

  3. Truy vấn logic HOẶC. Trong trường hợp này, bạn nên tạo một truy vấn riêng cho từng điều kiện HOẶC và hợp nhất các kết quả truy vấn trong ứng dụng của bạn.

  4. Truy vấn với mệnh đề a! =. Trong trường hợp này, bạn nên chia truy vấn thành truy vấn lớn hơn và truy vấn nhỏ hơn. Ví dụ: mặc dù mệnh đề truy vấn mà ("tuổi", "! =", "30") không được hỗ trợ, bạn có thể nhận được cùng một tập hợp kết quả bằng cách kết hợp hai truy vấn, một với mệnh đề where ("tuổi", "< "," 30 ") và một với mệnh đề where (" age ","> ", 30).


2
var songs = []    
db.collection('Dances')
      .where('songs.aNameOfASong', '==', true)
      .get()
      .then(function(querySnapshot) {
        var songLength = querySnapshot.size
        var i=0;
        querySnapshot.forEach(function(doc) {
           songs.push(doc.data())
           i ++;
           if(songLength===i){
                console.log(songs
           }
          console.log(doc.id, " => ", doc.data());
        });
       })
       .catch(function(error) {
         console.log("Error getting documents: ", error);
        });

1

Có thể tốt hơn nếu sử dụng cấu trúc dữ liệu phẳng.
Tài liệu chỉ rõ ưu và nhược điểm của các cấu trúc dữ liệu khác nhau trên trang này .

Cụ thể về những hạn chế của cấu trúc với tập hợp con:

Bạn không thể dễ dàng xóa các bộ sưu tập con hoặc thực hiện các truy vấn phức hợp trên các bộ sưu tập con.

Trái ngược với những lợi thế có chủ đích của cấu trúc dữ liệu phẳng:

Bộ sưu tập cấp gốc cung cấp tính linh hoạt và khả năng mở rộng cao nhất, cùng với khả năng truy vấn mạnh mẽ trong mỗi bộ sưu tập.


1

Tôi đã tìm thấy một giải pháp. Làm ơn kiểm tra cái này.

var museums = Firestore.instance.collectionGroup('Songs').where('songName', isEqualTo: "X");
        museums.getDocuments().then((querySnapshot) {
            setState(() {
              songCounts= querySnapshot.documents.length.toString();
            });
        });

Và sau đó, bạn có thể thấy các tab Dữ liệu, Quy tắc, Chỉ mục, Sử dụng trong firestore đám mây của mình từ console.firebase.google.com. Cuối cùng, bạn nên đặt các chỉ mục trong tab chỉ mục.nhập mô tả hình ảnh ở đây

Điền vào ID bộ sưu tập và một số giá trị trường tại đây. Sau đó Chọn tùy chọn nhóm bộ sưu tập. Hãy tận hưởng nó. Cảm ơn


Điều này không trả lời câu hỏi. Truy vấn được đề cập ở trên chỉ tìm nạp tất cả các Bài hát với songName = 'X'. Điều này sẽ không cung cấp các điệu nhảy nơi songName = 'X'.
sachin rathod

0

Tôi đang làm việc với Observables ở đây và trình bao bọc AngularFire nhưng đây là cách tôi quản lý để làm điều đó.

Thật là điên rồ, tôi vẫn đang tìm hiểu về những thứ có thể quan sát được và tôi có thể đã quá lạm dụng nó. Nhưng đó là một bài tập tốt.

Một số giải thích (không phải chuyên gia RxJS):

  • songId $ là một ứng dụng có thể quan sát sẽ phát ra id
  • dance $ là một hàm có thể quan sát đọc id đó và sau đó chỉ nhận giá trị đầu tiên.
  • sau đó nó truy vấn CollectionGroup của tất cả các bài hát để tìm tất cả các bản sao của nó.
  • Dựa trên các trường hợp mà nó truyền đến các Dances mẹ và lấy id của chúng.
  • Bây giờ chúng ta có tất cả id Dance, chúng ta cần truy vấn chúng để lấy dữ liệu của chúng. Nhưng tôi muốn nó hoạt động tốt vì vậy thay vì truy vấn từng cái một, tôi gộp chúng vào nhóm 10 (góc tối đa sẽ cần cho một intruy vấn.
  • Chúng tôi kết thúc với N nhóm và cần thực hiện N truy vấn trên firestore để nhận giá trị của chúng.
  • khi chúng tôi thực hiện các truy vấn trên firestore, chúng tôi vẫn cần thực sự phân tích cú pháp dữ liệu từ đó.
  • và cuối cùng chúng ta có thể hợp nhất tất cả các kết quả truy vấn để có được một mảng duy nhất với tất cả các Vũ điệu trong đó.
type Song = {id: string, name: string};
type Dance = {id: string, name: string, songs: Song[]};

const songId$: Observable<Song> = new Observable();
const dance$ = songId$.pipe(
  take(1), // Only take 1 song name
  switchMap( v =>
    // Query across collectionGroup to get all instances.
    this.db.collectionGroup('songs', ref =>
      ref.where('id', '==', v.id)).get()
  ),
  switchMap( v => {
    // map the Song to the parent Dance, return the Dance ids
    const obs: string[] = [];
    v.docs.forEach(docRef => {
      // We invoke parent twice to go from doc->collection->doc
      obs.push(docRef.ref.parent.parent.id);
    });
    // Because we return an array here this one emit becomes N
    return obs;
  }),
  // Firebase IN support up to 10 values so we partition the data to query the Dances
  bufferCount(10),
  mergeMap( v => { // query every partition in parallel
    return this.db.collection('dances', ref => {
      return ref.where( firebase.firestore.FieldPath.documentId(), 'in', v);
    }).get();
  }),
  switchMap( v => {
    // Almost there now just need to extract the data from the QuerySnapshots
    const obs: Dance[] = [];
    v.docs.forEach(docRef => {
      obs.push({
        ...docRef.data(),
        id: docRef.id
      } as Dance);
    });
    return of(obs);
  }),
  // And finally we reduce the docs fetched into a single array.
  reduce((acc, value) => acc.concat(value), []),
);
const parentDances = await dance$.toPromise();

Tôi sao chép, dán mã của mình và thay đổi tên biến thành của bạn, không chắc có lỗi nào không, nhưng nó hoạt động tốt với tôi. Hãy cho tôi biết nếu bạn tìm thấy bất kỳ lỗi nào hoặc có thể đề xuất cách tốt hơn để kiểm tra nó với một số cửa hàng firestore giả.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.