在Firebase中,扇出方法是否可以替换为ref.orderByChild(key).equalTo(value)?

在Firebase中,扇出方法是否可以替换为ref.orderByChild(key).equalTo(value)?,firebase,database,nosql,Firebase,Database,Nosql,在我的应用程序中,用户可以分组上传图片 有两个页面显示这些图片 我有两个要求 显示用户上载的图像列表 显示上载到组中的图像列表 从firebase教程中我了解到,数据扇出是一种很好的冗余机制,它将以写入速度为代价加快查找时间,写入速度很好,因为查找请求比写入请求多。所以我创建了以下结构 扇出法 { "user": [ {key: "user_key_1"}, {key: "user_key_2"}, {key: "user_key_3"},

在我的应用程序中,用户可以分组上传图片

有两个页面显示这些图片

我有两个要求

  • 显示用户上载的图像列表
  • 显示上载到组中的图像列表
  • 从firebase教程中我了解到,数据扇出是一种很好的冗余机制,它将以写入速度为代价加快查找时间,写入速度很好,因为查找请求比写入请求多。所以我创建了以下结构

    扇出法

    {
        "user": [
           {key: "user_key_1"},
           {key: "user_key_2"},
           {key: "user_key_3"},
        ],
        "group": [
           {key: "group_key_1"},
           {key: "group_key_2"}
       ],
        "post": [
           {
            key: "post_key_1"
            },
           {
            key: "post_key_2"
            },
           {
            key: "post_key_3"
            },
        ],
        "user-post": {
           user_key_1:[{
            key: "post_key_1"
           }],
           user_key_2:[{
            key: "post_key_2"
           },{
            key: "post_key_3"
           }]
        },
        "group-post": {
           group_key_1:[{
            key: "post_key_2"
           }],
           group_key_2:[{
            key: "post_key_1"
           },{
            key: "post_key_3"
           }]
        },
    }
    
    {
        "user": [
           {key: "user_key_1"},
           {key: "user_key_2"},
           {key: "user_key_3"},
        ],
        "group": [
           {key: "group_key_1"},
           {key: "group_key_2"},
       ],
        "post": [
           {
            key: "post_key_1"
            groupKey: "group_key_2"
            userKey: "user_key_1"
            },
           {
            key: "post_key_2"
            groupKey: "group_key_1"
            userKey: "user_key_2"
            },
           {
            key: "post_key_3"
            groupKey: "group_key_2"
            userKey: "user_key_2"
            }
        ]
    }
    
    检索代码

    String userKey = ...;
    database.child("user-post").child(userKey).addValueEventListener(...)
    // returns list of posts owned by userKey
    
    String groupKey = ...;
    database.child("group-post").child(groupKey).addValueEventListener(...)
    // returns list of posts posted on groupKey
    
    String userKey = ...;
    databaseReference.child("post").orderByChild("userKey").equalTo(userKey).addValueEventListener(...)
    // returns list of posts owned by userKey
    
    String groupKey = ...;
    databaseReference.child("post").orderByChild("groupKey").equalTo(groupKey).addValueEventListener(...)
    // returns list of posts posted on groupKey
    
    但是这引起了极大的头痛,因为如果您想更新帖子,并且您有来自组帖子查询的帖子引用,那么您必须更新用户帖子端,反之亦然

    这需要我将userKey和groupKey添加到post数据结构中,以便云函数能够快速找到另一端。此外,我可能需要类似lastUpdatedTimestamp的东西来查看谁过时了

    exports.userPostToBusinessPost = functions.database.ref('/user-post/{userKey}')
        .onWrite(event => {
          const userPostRef = event.data.val();
          const businessPostRef = event.data.adminRef.root.child('business-post').child(post.businessKey);
          if(userPostRef.lastUpdatedTimestamp <= businessPostRef.lastUpdatedTimestamp){
              return;
          }else{
              return businessPost.set(event.data);
          }
        });
    
    exports.businessPostToUserPost = functions.database.ref('/business-post/{businessKey}')
        .onWrite(event => {
          const businessPostRef = event.data.val();
          const userPostRef = event.data.adminRef.root.child('user-post').child(post.userKey);
          if(userPostRef.lastUpdatedTimestamp <= businessPostRef.lastUpdatedTimestamp){
              return;
          }else{
              return userPostRef.set(event.data);
          }
        });
    
    检索代码

    String userKey = ...;
    database.child("user-post").child(userKey).addValueEventListener(...)
    // returns list of posts owned by userKey
    
    String groupKey = ...;
    database.child("group-post").child(groupKey).addValueEventListener(...)
    // returns list of posts posted on groupKey
    
    String userKey = ...;
    databaseReference.child("post").orderByChild("userKey").equalTo(userKey).addValueEventListener(...)
    // returns list of posts owned by userKey
    
    String groupKey = ...;
    databaseReference.child("post").orderByChild("groupKey").equalTo(groupKey).addValueEventListener(...)
    // returns list of posts posted on groupKey
    

    我还应该使用扇出方法吗?是不是因为“orderByChild”的成本很高?如果是这样,为什么Firebase会有一种隐式扇出机制,在这种机制中,只要我们保存一些数据,任何json对象都会按其所有子键进行排序,这样开发人员就不必自己管理扇出?

    假设您希望用户拥有对自己拥有的帖子的读取权限

    我们有

    "post": [
           {
            key: "post_key_1"
            groupKey: "group_key_2"
            userKey: "user_key_1"
            },
           {
            key: "post_key_2"
            groupKey: "group_key_1"
            userKey: "user_key_2"
            },
           {
            key: "post_key_3"
            groupKey: "group_key_2"
            userKey: "user_key_2"
            }
        ]
    
    用户\密钥\ 1想要访问post。 但我们不想让她看到用户2。 如果我们想使用orderBy,我们必须打电话

    ...
    .child("post").orderBy("userKey").equalTo("user_key_2");
    
    但是,由于我们不能在值(在本例中为post数组)中给出选择性验证规则,因此我们最终不得不执行以下操作

    "post":{
       .read:true,
       .write:true
    }
    
    恶意黑客可以访问其他东西,因此我们最终将得到一个可以公开的数据库。 因此,要按预期方式使用验证规则,请避免orderBy,并使用数据复制

    对认为应该在服务器端执行的任何人的提示, 我是这样做的

    exports.multiUpdate=functions.database.ref('/post/{postKey}').onWrite(事件=>{ var post=event.data.val()

    var fanoutObject={}

        fanoutObject['/user-post/'+ post.authorUid+"/"+post.key] = post;
        fanoutObject['/group-post/'+post.groupKey+"/"+post.key] = post;
    
       return event.data.adminRef.root.update(fanoutObject);
    
    }))

    这种方式很好,因为您只需始终保存到客户端的“/post/”上,这也会更新相应的位置