代码之家  ›  专栏  ›  技术社区  ›  Paco Zevallos

获取字段子集合Firestore[副本]

  •  0
  • Paco Zevallos  · 技术社区  · 6 年前

    我以为我读到你可以用新的Firebase Firestore查询子集合,但是我没有看到任何例子。例如,我的Firestore设置如下:

    • 舞蹈[集]
      • 舞池
      • 歌曲[收藏]
        • 歌名

    我怎样才能查询“查找歌曲名为'X'的所有舞蹈”

    0 回复  |  直到 7 年前
        1
  •  141
  •   Frank van Puffelen    5 年前

    更新2019-05-07

    今天我们发布了 collection group queries ,这些允许您跨子集合进行查询。

    例如,在web SDK中:

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

    这将匹配任何集合中的文档,其中集合路径的最后一部分是“Songs”。

    你最初的问题是 舞蹈 其中songName='X',但这仍然不能直接实现,但是,对于匹配的每首歌,可以加载其父歌。

    原始答案

    这是一个尚不存在的特性。它被称为“集合组查询”,允许您查询所有歌曲,而不必考虑包含这些歌曲的舞蹈。这是我们打算支持的,但还没有具体的时间表。

    在这一点上,另一种结构是使歌曲成为顶级收藏,并使歌曲的舞蹈成为歌曲属性的一部分。

        2
  •  22
  •   norgematos    6 年前

    更新 现在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);
    

    我希望这能有帮助。

        3
  •  14
  •   dmartins    7 年前

    如果将歌曲存储为对象而不是集合,会怎么样?每个舞蹈作为,以歌曲作为字段:类型对象(不是集合)

    {
      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);
        });
    
        4
  •  14
  •   Matthew Mullin    5 年前

    2019年更新

    Firestore已经发布了集合组查询。见上面吉尔的回答或官方 Collection Group Query Documentation


    上一个答案

    正如吉尔伯特所说,似乎 集合组查询 目前正在进行中。同时,最好使用根级集合,并使用文档UID在这些集合之间建立链接。

    对于那些还不知道的人,Jeff Delaney为任何在Firebase(和Angular)上工作的人提供了一些令人难以置信的指南和资源 AngularFirebase .

    Firestore NoSQL Relational Data Modeling -在这里,他分解了NoSQL和Firestore数据库结构的基础知识

    Advanced Data Modeling With Firestore by Example -这些都是更先进的技术留在你的脑海里。对于那些想把他们的消防技能提升到一个新水平的人来说,这是一本很好的读物

        5
  •  7
  •   Nhật Trần    5 年前

    2019年7月8日最新更新:

    db.collectionGroup('Songs')
      .where('songName', isEqualTo:'X')
      .get()
    
        6
  •  3
  •   Ankur    6 年前

    你总是可以像这:-

    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;
          }
        })
    );
    
        7
  •  3
  •   ggDeGreat    6 年前

    查询限制

    Cloud Firestore不支持以下类型的查询:

    1. 对不同字段使用范围筛选器的查询。

    2. 跨多个集合或子集合的单个查询。每个查询针对单个文档集合运行。更多 有关数据结构如何影响查询的信息,请参见 Choose a Data Structure .

    3. 逻辑或查询。在这种情况下,应该为每个或条件创建单独的查询,并在应用程序中合并查询结果。
    4. 用a查询!=条款。在这种情况下,应该将查询拆分为大于查询和小于查询。例如,尽管 查询子句的位置(“age”,“!不支持“,”30“),您可以 通过组合两个查询(一个查询与子句)获得相同的结果集 其中(“age”、“<”、“30”)和一个带有子句where(“age”、“>”、30)。
        8
  •  2
  •   Alok Prusty    6 年前
    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);
            });
    
        9
  •  1
  •   MattCochrane    6 年前

    最好使用平面数据结构。
    文档详细说明了不同数据结构的优缺点 on this page .

    特别是子集合结构的限制:

    不能轻松删除子集合,也不能跨子集合执行复合查询。

    与所谓的扁平数据结构的优点相比:

    根级集合提供了最大的灵活性和可伸缩性,以及每个集合内的强大查询。

        10
  •  1
  •   Happy Son    5 年前

    我找到了解决办法。 请检查一下。

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

    然后,您可以从控制台.firebase.google.com.网站。 最后,应该在“索引”选项卡中设置索引。 enter image description here

    在这里填写集合ID和一些字段值。 然后选择“集合组”选项。 好好享受吧。谢谢

        11
  •  0
  •   Eduardo    4 年前

    我正在研究这里的观测数据 AngularFire 包装纸,但这是我怎么做到的。

    这有点疯狂,我仍然在学习观察,我可能做得太过头了。但这是个不错的练习。

    一些解释(不是RxJS专家):

    • songId$是一个可以发出id
    • dance$是一个可观察的值,它读取该id,然后只获取第一个值。
    • 然后,它查询所有歌曲的collectionGroup以查找其所有实例。
    • 基于实例,它遍历父舞蹈并获取它们的id。
    • 现在我们有了所有的舞蹈ID,我们需要查询它们以获取数据。但我希望它能表现得很好,所以我不是一个一个地查询,而是把它们成批地放在10个桶里(最大角度是 in 查询。
    • 我们最终得到了N个bucket,需要在firestore上执行N个查询来获取它们的值。
    • 一旦我们在firestore上进行了查询,我们仍然需要从中实际解析数据。
    • 最后,我们可以合并所有的查询结果,得到一个包含所有舞蹈的数组。
    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();
    
    

    我复制粘贴了我的代码,并将变量名更改为您的,不确定是否有任何错误,但它对我很好。如果你发现任何错误,或者可以建议一个更好的方法来测试它,也许一些模拟消防商店。