如何使用firestore在angularfire2中绑定多个查询结果? [英] How to bind multiple query results in angularfire2 with firestore?

查看:203
本文介绍了如何使用firestore在angularfire2中绑定多个查询结果?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想使用一个集合来维护一些文档之间的关系,如这里(但略有修改的方法)。我选择了收集方法,因为它随着时间的推移似乎更具可扩展性,即文档属性。



我的实际数据结构

 用户
user1
user2

公司
co1
co2

user_co
user1
公司(集合)
co1
co2

user2
公司(集合)
co1

但是采用这种方法,我需要执行多个查询才能获取特定用户的所有可用公司,因为我们无法执行IN 条款。

因此我需要分两步检索数据:
$ b $ ol

  • 检索公司用户的列表可以访问 user_co / {user} / companies

  • /公司/ {id}

  • 为什么需要2个步骤?因为我不想为所有用户提供所有公司的读取访问权限,并且查询 / companies 会触发访问错误。



    所以我对如何检索从多个调用检索到的文档的单个可绑定列表感到困惑?



    我的组件中显示了2个项目,但字段值的确如此没有得到显示。我在检索/公司文件的方式上肯定做错了。



    任何帮助都将不胜感激。



    MyService.ts




    $ b

    interface公司{
    名称:string;
    所有者:any;
    id ?: any;
    时间?:任何;
    creationTime ?: any;
    }

    接口MyCompany {
    id ?: any;
    名称:string;


    @Injectable()
    export class CompanyService {

    companiesCollection:AngularFirestoreCollection< Company> ;;
    myCompaniesCollection:AngularFirestoreCollection< MyCompany>;
    myCompanies;

    构造函数(private afs:AngularFirestore,private ats:AuthService){

    this.myCompaniesCollection = this.afs.collection('user_co')。doc(this.ats。 currentUserId).collection( '公司');
    this.myCompanies = this.myCompaniesCollection.snapshotChanges()。map(actions => {
    return actions.map(a => {
    //什么是检索的好方法/公司数据来自这里?
    返回this.afs.firestore.collection(companies)。doc(a.payload.doc.id).get()。then(doc => {
    返回{id:doc.id,... doc.data()}
    })。catch(error => {
    console.log(Error reading company document:,error);
    });
    //从/ user_co返回数据的原始示例
    //返回{id:a.payload.doc.id,... a.payload.doc.data( )}
    })
    });
    }

    getData(){
    return this.myCompanies;


    $ / code>

    使用angularfire2 5.0.0-rc.3 with firebase 4.5.2

    解决方案

    我终于改变了将数据存储到Firestore的方式。 b $ b

    正如此处所述在许多与NoSQL相关的文档中,非规范化是避免加入like和多个查询的方式。


    使用非规范化将处理
    a查询所需的所有数据分组在一个地方。这通常意味着对于不同的查询流
    ,将以不同的组合访问相同的数据。因此,我们
    需要复制数据,这会增加总数据量。

    这样,我可以简单地检索 / users / {user} / companies ,并获取有关公司用户所属的所有相关信息。并且无需为所有用户访问所有公司信息(设置,用户等)。



    新的数据结构

      / users / {user} 
    user_name
    / companies / {company}
    company_name

    / companies / {company}
    name
    / admins / {user}
    / users / {user}
    user_name

    允许管理员邀请/添加用户到公司的安全规则

      match / users / {usr} / companies / {co} {
    //只对实际用户可见
    允许读取:if request.auth.uid == usr;

    //当前用户可以选择退出公司
    允许删除:if request.auth.uid == usr ||
    //公司管理员可以添加或删除用户
    存在(/ databases / $(db)/ documents / companies / $(co)/ admins / $(request.auth.uid)) ;

    //公司管理员可以添加或删除用户
    允许创建,更新:if exists(/ databases / $(db)/ documents / companies / $(co)/ admins /$(request.auth.uid));

    $ b $匹配/公司/ {co} {
    //公司只有会员和管理员可以访问
    允许阅读:如果存在
    (/数据库/$(db)/documents/companies/$(co)/members/$(request.auth.uid))||
    存在(/ databases / $(db)/ documents / companies / $(co)/ admins / $(request.auth.uid));

    match / admins / {usr} {
    //允许公司创建,如果它不存在
    允许创建:if exists(/ databases / $(db)/ documents / (/ database / $(db)/ documents / companies / $(co)/ admins)/ $(co))== false
    /$(request.auth.uid));

    match / users / {usr} {
    //允许管理员写入
    允许写入:if exists(/ databases / $(db)/ documents / companies / $ (共)/管理员/ $(request.auth.uid));
    }
    }

    配对



    在更新 / companies / {company} / [name] 时,我还需要检索属于该公司的所有用户通过 / companies / {company} / users ,然后更新 / users / {user} / companies / {company} 。这可以在一个交易中完成。


    I would like to use a collection to maintain relation between some documents as proposed here (but slightly modified approach). I have chosen collection approach because it seems more scalable that document properties over time.

    My actual data scructure

    users
       user1
       user2
    
    companies
       co1
       co2
    
    user_co
       user1
           companies (collection)
               co1
               co2
    
       user2
           companies (collection)
               co1
    

    But with that approach, I need to do multiple queries in order to get all available companies for a specific user as we cannot perform "IN" clause.

    So I need retrieve data in 2 steps:

    1. retrieve list of company user have access to in user_co/{user}/companies
    2. retrieve actual companies from /companies/{id}

    Why 2 steps? Because I don't want to give read access to all companies to all users and querying /companies would then trigger access error­.

    So I got struggle with how to retrieve a single bindable list of documents retrieved from multiple calls?

    I got 2 items displayed in my component but field values does not get displayed. I certainly do something wrong in the way I retrieve /company documents.

    Any help would be greatly appreciated.

    MyService.ts

    interface Company {
        Name: string;
        Owner: any;
        id?: any;
        time?: any;
        creationTime?: any;
    }
    
    interface MyCompany {
        id?: any;
        Name: string;
    }
    
    @Injectable()
    export class CompanyService {
    
        companiesCollection: AngularFirestoreCollection<Company>;
        myCompaniesCollection: AngularFirestoreCollection<MyCompany>;
        myCompanies;
    
        constructor(private afs: AngularFirestore, private ats: AuthService) {
    
            this.myCompaniesCollection = this.afs.collection('user_co').doc(this.ats.currentUserId).collection('companies');
            this.myCompanies = this.myCompaniesCollection.snapshotChanges().map(actions => {
                return actions.map(a => {
                    // What is the good way to retrieve /companies data from here?
                    return this.afs.firestore.collection("companies").doc(a.payload.doc.id).get().then(doc => {
                        return { id: doc.id, ...doc.data() }
                    }).catch(error => {
                        console.log("Error reading company document:", error);
                    });
                    // Original example that return data from /user_co
                    //return { id: a.payload.doc.id, ...a.payload.doc.data() }
                })
            });
        }
    
        getData() {
            return this.myCompanies;
        }
    }
    

    using angularfire2 5.0.0-rc.3 with firebase 4.5.2

    解决方案

    I've finally changed the way I store data into Firestore.

    As mentionned here and in many docs related to NoSQL, denormalization is the way to go to avoid "join like" and multiple queries.

    Using denormalization one can group all data that is needed to process a query in one place. This often means that for different query flows the same data will be accessed in different combinations. Hence we need to duplicate data, which increases total data volume.

    That way, I can simply retrieve /users/{user}/companies and get all relevant info about companies user belongs to. And there is no need to be able to access all company info (settings, users, etc) for all users anyway.

    New data structure

    /users/{user}
        user_name
        /companies/{company}
           company_name
    
    /companies/{company}
        name
        /admins/{user}
        /users/{user}
            user_name
    

    Security rules allowing admins to invite/add users to company

    match /users/{usr}/companies/{co} {
        // Only visible to the actual user
        allow read: if request.auth.uid == usr;
    
        // Current user can opt-out of company
        allow delete: if request.auth.uid == usr ||
            // Company admin can add or drop-out a user
            exists(/databases/$(db)/documents/companies/$(co)/admins/$(request.auth.uid));
    
        // Company admin can add or drop-out a user
        allow create, update: if exists(/databases/$(db)/documents/companies/$(co)/admins/$(request.auth.uid));
    }
    
    match /companies/{co} {
        // Company accessible for members and admins only
        allow read: if
            exists(/databases/$(db)/documents/companies/$(co)/members/$(request.auth.uid)) || 
                exists(/databases/$(db)/documents/companies/$(co)/admins/$(request.auth.uid));
    
        match /admins/{usr} {
            // allow company creation if it does not exists
            allow create: if exists(/databases/$(db)/documents/companies/$(co)) == false
            // updates allowed for admins
            allow update, delete: if exists(/databases/$(db)/documents/companies/$(co)/admins/$(request.auth.uid));
        }
        match /users/{usr} {
          // writes allowed for admins
          allow write: if exists(/databases/$(db)/documents/companies/$(co)/admins/$(request.auth.uid));
        }
    }
    

    Counterpart

    When updating /companies/{company}/[name], I also need to retrieve all users that belongs to that company through /companies/{company}/users and then update all docs in /users/{user}/companies/{company}. This can be made within a single transaction.

    这篇关于如何使用firestore在angularfire2中绑定多个查询结果?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆