Answers:
更新2019-05-07
今天,我们发布了集合组查询,这些查询使您可以跨子集合进行查询。
因此,例如在Web SDK中:
db.collectionGroup('Songs')
  .where('songName', '==', 'X')
  .get()
这将匹配集合路径的最后部分为“歌曲”的任何集合中的文档。
您最初的问题是关于在songName =='X'处查找舞蹈,但是仍然不可能直接实现,但是,对于匹配的每首歌曲,您都可以加载其父项。
原始答案
此功能尚不存在。这称为“收藏组查询”,无论您跳舞的是哪种歌曲,都可以查询所有歌曲。这是我们打算支持的事情,但没有具体的时间表。
此时的另一种结构是使歌曲成为顶级收藏,并使歌曲以哪种舞蹈成为歌曲属性的一部分。
立即更新 Firestore支持数组包含
拥有这些文件
    {danceName: 'Danca name 1', songName: ['Title1','Title2']}
    {danceName: 'Danca name 2', songName: ['Title3']}
这样做
collection("Dances")
    .where("songName", "array-contains", "Title1")
    .get()...
@ Nelson.b.austin由于Firestore还没有,所以我建议您使用扁平结构,这意味着:
Dances = {
    danceName: 'Dance name 1',
    songName_Title1: true,
    songName_Title2: true,
    songName_Title3: false
}
以这种方式拥有它,您可以完成它:
var songTitle = 'Title1';
var dances = db.collection("Dances");
var query = dances.where("songName_"+songTitle, "==", true);
我希望这有帮助。
songName_Title3: false用?如果我没记错的话,它只能用于搜索没有特定歌曲名称的舞蹈,前提是我们需要a songName_Title3: false来dances.where("songName_"+songTitle, "==", false); 返回这样的结果,这样就不会让每个舞蹈都为每个可能的歌曲都带有布尔标志名称...
                    如果您将歌曲存储为对象而不是收藏,该怎么办?每个舞蹈都以歌曲为字段:键入Object(不是集合)
{
  danceName: "My Dance",
  songs: {
    "aNameOfASong": true,
    "aNameOfAnotherSong": true,
  }
}
那么您可以使用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);
    });
更新2019
Firestore已发布集合组查询。请参阅上述Gil的答案或官方的“ 收藏组查询”文档
上一个答案
正如吉尔·吉尔伯特(Gil Gilbert)所说,似乎 正在进行集合组查询。同时,最好使用根级别集合,并仅使用文档UID在这些集合之间进行链接。
对于那些尚不了解的人,Jeff Delaney为在AngularFirebase上使用Firebase(和Angular)的任何人提供了一些不可思议的指南和资源。
Firestore NoSQL关系数据建模 -在这里他分解了NoSQL和Firestore DB结构化的基础知识
通过示例使用Firestore进行高级数据建模 -这些是更先进的技术,可让您牢记在心。对于那些希望将其Firestore技能提高到一个新水平的人来说是一本好书
您总是可以这样搜索:
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;
      }
    })
);
查询限制
Cloud Firestore不支持以下类型的查询:
在不同字段上具有范围过滤器的查询。
跨多个集合或子集合的单个查询。每个查询针对单个文档集合运行。有关数据结构如何影响查询的更多信息,请参见 选择数据结构。
逻辑或查询。在这种情况下,您应该为每个OR条件创建一个单独的查询,并将查询结果合并到您的应用中。
带!=子句的查询。在这种情况下,您应该将查询分为大于查询和小于查询。例如,尽管不支持查询子句where(“ age”,“!=”,“ 30”),但您可以通过组合两个查询获得相同的结果集,其中一个查询与子句where(“ age”,“ < “,” 30“)和带有子句where(” age“,”>“,30)的子句。
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);
        });
我找到了解决方案。请检查一下。
var museums = Firestore.instance.collectionGroup('Songs').where('songName', isEqualTo: "X");
        museums.getDocuments().then((querySnapshot) {
            setState(() {
              songCounts= querySnapshot.documents.length.toString();
            });
        });
然后,您可以从console.firebase.google.com在Cloud Firestore中查看“数据”,“规则”,“索引”,“使用情况”选项卡。最后,您应该在“索引”选项卡中设置索引。
在此处填写集合ID和一些字段值。然后选择收集组选项。好好享受。谢谢
我在这里使用Observables和AngularFire包装器,但是这是我设法做到的方法。
这有点疯狂,我仍在学习有关可观察物的信息,但我可能过时了。但这是一个很好的练习。
一些解释(不是RxJS专家):
in查询需要最大角度)。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();
我复制粘贴了我的代码,并将变量名更改为您的变量名,不确定是否有任何错误,但是对我来说很好。让我知道您是否发现任何错误,或者可以建议一个更好的方法来进行模拟Firestore测试。