【问题标题】:Retrieve all documents from just one known subcollection仅从一个已知子集合中检索所有文档
【发布时间】:2018-10-29 05:09:42
【问题描述】:

我有这个 Firestore 结构:

Category: {
    document1a: {
        name : "reptiles"
        animalsubcollection: {
            Document1b: {
                name: "snake"
                color: "white"
            }
            Document2b: {
                name: "lizard"
                color: "black"
            }
    document2a: {
        name : "mammals"
        animalsubcollection: {
            Document1b: {
                name: "monkey"
                color: "brown"
            }
            Document2b: {
                name: "cat"
                color: "white"
            }

我需要在一个页面中列出该信息,按类别分类如下:

爬行动物:

  • 蛇:白
  • 蜥蜴:黑色

哺乳动物:

  • 猴子:棕色
  • 猫:白

与上面的示例一样,我总是只有一个名为 animalsubcollection 的已知子集合。

如何在 Angular 5 中使用 AngularFire2 来实现这一点?

如果它不是此类信息的最佳 Firestore 模型,我可以在必要时更改它。我接受其他人的建议以达到相同的结果。

【问题讨论】:

    标签: angular firebase ionic3 google-cloud-firestore angularfire2


    【解决方案1】:

    感谢大家的建议,但最初的建议不是对原始数据库模型进行规范化,而是使用原始模型找到一个简单的解决方案。

    我知道有时候,只需简单地创建 2 或 3 个新的规范化集合并解决问题就更容易了。另一方面,如果有可能创建一个子集合,它需要存在一种以 Angular em RxJS 方式查询他的数据的方法。

    所以,经过 2 或 3 天的研究,我找到了一种方法:

    //necessary imports
    import { Observable } from 'rxjs/observable';
    import { combineLatest } from 'rxjs/observable/combineLatest';
    import 'rxjs/add/operator/mergeMap';
    
    // the observable for animals category collection
    this.animals = this.afs
      .collection('Category')
      .snapshotChanges()
      .map(arr => {
        return arr.map(snap => {
          const categ = { id: snap.payload.doc.id, ...snap.payload.doc.data() };
    
          // the animalsubcollection, using the previous value as parameter
          return this.afs
            .collection(`Category/${categ.id}/animalsubcollection`)
            .valueChanges()
            .map(animalsub => {
              return { ...categ, animalSubs: animalsub };
            });
        });
      })
      .mergeMap(result => combineLatest(result));
      //thats the trick. Combine 2 observables into a new one.
    

    在视图中:

    <ion-card *ngFor="let animal of animals | async">
    <p *ngFor="let as of animal.animalSubs">
         {{as.name}} - {{as.color}}
    </p>
    

    希望对大家有所帮助

    【讨论】:

    • 最新 angularfire 库中“map”的使用已经改变......需要像这个例子一样添加“管道”:this.afs.collection('Category').snapshotChanges()。管道(地图(arr => { ... }))
    【解决方案2】:

    假设您有一个有效的 JSON 数组(您发布的那个无效)您可以使用 Angular 以一种非常简单的方式完成此操作。

    您可以在 Angular 应用中使用下划线轻松存档。

    how to use underscore.js library in angular 2

    groupedSeriesNames = []
    groupedSeries = []
    
    
    
    categories =  Category: {
            document1a: {
                name : "reptiles"
                animalsubcollection: {
                    Document1b: {
                        name: "snake"
                        color: "white"
                    }
                    Document2b: {
                        name: "lizard"
                        color: "black"
                    }
            document2a: {
                name : "mammals"
                animalsubcollection: {
                    Document1b: {
                        name: "monkey"
                        color: "brown"
                    }
                    Document2b: {
                        name: "cat"
                        color: "white"
                    }
               .
               .
               .
    

    更好的数据结构示例:

    {
            type: "reptiles",       
            name: "snake",
            color: "white"
    
    
        },
        {
            type: "reptiles",       
            name: "snake",
            color: "white"
        },
        {
            type: "mammals",        
            name: "snake",
            color: "white"
        }
    }
    

    {
            name: "reptiles",
            animalsubcollection: {
                Document1b: {
                    name: "snake",
                    color: "white"
                }
            }
        },
        {
            name: "mammals",
            animalsubcollection: {
                Document1b: {
                    name: "leion",
                    color: "white"
                }
            }
        },
        {
            name: "mammals",
            animalsubcollection: {
                Document1b: {
                    name: "papa",
                    color: "white"
                }
            }
        }
    this.groupedTypes = _.groupBy(this.categories, category=>category.name);
    this.groupedSeriesNames = Object.keys(this.groupedSeries)
    

    certificate.serie 将成为他们的密钥,您可以将 certificate.serie 更改为任何其他属性,例如 iden 或任何您需要的属性

    你的html

    <ul class="cert-result">
        <li *ngFor="let key of groupedSeriesNames">
          <table *ngFor="let category of groupedSeries[key]">
            <tr>
              <th>Name</th>
              <th>Color</th>
            </tr>
            <tr>
              <td>{{category.color}}</td>
              <td>{{category.name}}</td>
            </tr>
          </table>
        </li>
      </ul>
    

    不使用下划线的代码(假设 json 结构正确)

    function formatedCerts() {
          return categories.reduce((prev, now) => {
            if (!prev[now.name]) {
              prev[now.name] = [];
            }
    
            prev[now.name].push(now);
            return prev;
          }, {});
    }
    

    【讨论】:

    • 我不想使用外部 js 库。我希望有一种本地方法可以做到这一点。
    • 乔尔,可以理解,你可以看看我更新的答案。让你的 json 结构正确。仅供参考,下划线非常常用
    • @joel 人们使用下划线,因为它非常易于使用,而且您可以获得可读的代码
    【解决方案3】:

    我建议您规范化您的数据结构。你可以遵循这个模式:https://redux.js.org/recipes/structuring-reducers/normalizing-state-shape

    在您的数据结构的一个节点中,存储您拥有的所有“动物”。另外,存储所有“动物类别”。或者,存储它们之间的关系,为每个类别关联动物“键”。

    {
        animals: {
            snake: { color: 'white '},
            lizard: { color: 'black' },
            monkey: { color: 'brown '}
        },
        categories: {
            reptiles: { description: 'something here about reptiles'},
            mammals:  { description: 'something here about mammals'}
        },
        animals_categories: {
            reptiles: ['snake', 'lizard'],
            mammals: ['monkey']
        }
    
    }
    

    因此您将能够查询类别,然后使用每个类别的动物键,您将能够获取动物详细信息。 虽然我提供的链接来自 Redux 的文档,但这种模式并不绑定到 Redux。这是基于文档的此类数据结构中的常见用法。

    【讨论】:

    • 这不是一个有效的答案,因为您假设他知道集合中的内容。他提到“我总是只有一个已知的子集合,称为 animalsubcollection”
    • 我也认为这种标准化不是最好的方法。 animals_categories 仅在动物属于一个以上类别时才需要。这不是真的。无论如何感谢您的回复。
    • IMO 这是一个很好的方法,因为每种信息都有单独的节点。一个用于类别,一个用于动物,另一个用于关系。只属于一个类别的动物不是问题。使用这种结构,可以轻松获取每种类型的数据,并且您没有嵌套对象(有时可能是一种“嵌套地狱”),每个节点中只有一个级别的数据。
    • 我同意@ChristianBenseler,您的数据需要清理一下
    • 这很接近,但我会合并 categoriesanimals_categories 的属性,因为它们是同义词。
    猜你喜欢
    • 1970-01-01
    • 2021-10-26
    • 1970-01-01
    • 2021-10-30
    • 1970-01-01
    • 1970-01-01
    • 2018-06-18
    • 1970-01-01
    • 2021-08-16
    相关资源
    最近更新 更多