database 在 Firebase 中,有没有办法在不加载所有节点数据的情况下获取节点的子节点数?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15148803/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-08 08:52:36  来源:igfitidea点击:

In Firebase, is there a way to get the number of children of a node without loading all the node data?

databasefirebasecount

提问by josh

You can get the child count via

您可以通过以下方式获得孩子数

firebase_node.once('value', function(snapshot) { alert('Count: ' + snapshot.numChildren()); });

But I believe this fetches the entire sub-tree of that node from the server. For huge lists, that seems RAM and latency intensive. Is there a way of getting the count (and/or a list of child names) without fetching the whole thing?

但我相信这会从服务器获取该节点的整个子树。对于庞大的列表,这似乎是 RAM 和延迟密集型的。有没有办法在不获取整个内容的情况下获取计数(和/或子名称列表)?

采纳答案by Andrew Lee

The code snippet you gave does indeed load the entire set of data and then counts it client-side, which can be very slow for large amounts of data.

您提供的代码片段确实加载了整个数据集,然后在客户端对其进行计数,这对于大量数据来说可能非常慢。

Firebase doesn't currently have a way to count children without loading data, but we do plan to add it.

Firebase 目前无法在不加载数据的情况下计算孩子的数量,但我们确实计划添加它。

For now, one solution would be to maintain a counter of the number of children and update it every time you add a new child. You could use a transaction to count items, like in this code tracking upvodes:

目前,一种解决方案是维护一个孩子数量的计数器,并在每次添加新孩子时更新它。您可以使用事务来计算项目,例如在此代码中跟踪 upvodes:

var upvotesRef = new Firebase('https://docs-examples.firebaseio.com/android/saving-data/fireblog/posts/-JRHTHaIs-jNPLXOQivY/upvotes');
upvotesRef.transaction(function (current_value) {
  return (current_value || 0) + 1;
});

For more info, see https://www.firebase.com/docs/transactions.html

有关更多信息,请参阅https://www.firebase.com/docs/transactions.html

UPDATE:Firebase recently released Cloud Functions. With Cloud Functions, you don't need to create your own Server. You can simply write JavaScript functions and upload it to Firebase. Firebase will be responsible for triggering functions whenever an event occurs.

更新:Firebase 最近发布了 Cloud Functions。使用 Cloud Functions,您无需创建自己的服务器。您可以简单地编写 JavaScript 函数并将其上传到 Firebase。Firebase 将负责在事件发生时触发函数。

If you want to count upvotes for example, you should create a structure similar to this one:

例如,如果您想计算投票数,您应该创建一个类似于以下的结构:

{
  "posts" : {
    "-JRHTHaIs-jNPLXOQivY" : {
      "upvotes_count":5,
      "upvotes" : {
      "userX" : true,
      "userY" : true,
      "userZ" : true,
      ...
    }
    }
  }
}

And then write a javascript function to increase the upvotes_countwhen there is a new write to the upvotesnode.

然后编写一个javascript函数来增加节点upvotes_count的新写入upvotes

const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);

exports.countlikes = functions.database.ref('/posts/$postid/upvotes').onWrite(event => {
  return event.data.ref.parent.child('upvotes_count').set(event.data.numChildren());
});

You can read the Documentationto know how to Get Started with Cloud Functions.

您可以阅读文档以了解如何开始使用 Cloud Functions

Also, another example of counting posts is here: https://github.com/firebase/functions-samples/blob/master/child-count/functions/index.js

此外,另一个计算帖子的例子在这里:https: //github.com/firebase/functions-samples/blob/master/child-count/functions/index.js

Update January 2018

2018 年 1 月更新

The firebase docshave changed so instead of eventwe now have changeand context.

火力文档已经改变所以不是event我们现在有changecontext

The given example throws an error complaining that event.datais undefined. This pattern seems to work better:

给定的示例抛出一个错误,抱怨event.data未定义。这种模式似乎效果更好:

exports.countPrescriptions = functions.database.ref(`/prescriptions`).onWrite((change, context) => {
    const data = change.after.val();
    const count = Object.keys(data).length;
    return change.after.ref.child('_count').set(count);
});

```

``

回答by Alex Klibisz

This is a little late in the game as several others have already answered nicely, but I'll share how I might implement it.

这在游戏中有点晚了,因为其他几个人已经很好地回答了,但我将分享我如何实现它。

This hinges on the fact that the Firebase REST APIoffers a shallow=trueparameter.

这取决于Firebase REST API提供shallow=true参数的事实。

Assume you have a postobject and each one can have a number of comments:

假设您有一个post对象,每个对象都可以有多个comments

{
 "posts": {
  "$postKey": {
   "comments": {
     ...  
   }
  }
 }
}

You obviously don't want to fetch all of the comments, just the number of comments.

您显然不想获取所有评论,只想获取评论数量。

Assuming you have the key for a post, you can send a GETrequest to https://yourapp.firebaseio.com/posts/[the post key]/comments?shallow=true.

假设您拥有帖子的密钥,您可以向 发送GET请求 https://yourapp.firebaseio.com/posts/[the post key]/comments?shallow=true

This will return an object of key-value pairs, where each key is the key of a comment and its value is true:

这将返回一个键值对对象,其中每个键是评论的键,其值为true

{
 "comment1key": true,
 "comment2key": true,
 ...,
 "comment9999key": true
}

The size of this response is much smaller than requesting the equivalent data, and now you can calculate the number of keys in the response to find your value (e.g. commentCount = Object.keys(result).length).

此响应的大小比请求等效数据小得多,现在您可以计算响应中的键数以找到您的值(例如 commentCount = Object.keys(result).length)。

This may not completely solve your problem, as you are still calculating the number of keys returned, and you can't necessarily subscribe to the value as it changes, but it does greatly reduce the size of the returned data without requiring any changes to your schema.

这可能不能完全解决您的问题,因为您仍在计算返回的键的数量,并且您不一定会在值更改时订阅该值,但它确实大大减少了返回数据的大小,而无需对您的数据进行任何更改架构。

回答by pperrin

Save the count as you go - and use validation to enforce it. I hacked this together - for keeping a count of unique votes and counts which keeps coming up!. But this time I have tested my suggestion! (notwithstanding cut/paste errors!).

随时保存计数 - 并使用验证来执行它。我一起破解了这个 - 保持独特的投票计数和不断出现的计数!。但是这次我测试了我的建议!(尽管有剪切/粘贴错误!)。

The 'trick' here is to use the node priorityto as the vote count...

这里的“技巧”是使用节点优先级作为投票计数......

The data is:

数据是:

vote/$issueBeingVotedOn/user/$uniqueIdOfVoter = thisVotesCount, priority=thisVotesCount vote/$issueBeingVotedOn/count = 'user/'+$idOfLastVoter, priority=CountofLastVote

投票/$issueBeingVotedOn/user/$uniqueIdOfVoter = thisVotesCount,priority=thisVotesCount 投票/$issueBeingVotedOn/count = 'user/'+$idOfLastVoter,priority=CountofLastVote

,"vote": {
  ".read" : true
  ,".write" : true
  ,"$issue" : {
    "user" : {
      "$user" : {
        ".validate" : "!data.exists() && 
             newData.val()==data.parent().parent().child('count').getPriority()+1 &&
             newData.val()==newData.GetPriority()" 

user can only vote once && count must be one higher than current count && data value must be same as priority.

用户只能投票一次 && 计数必须比当前计数高 1 && 数据值必须与优先级相同。

      }
    }
    ,"count" : {
      ".validate" : "data.parent().child(newData.val()).val()==newData.getPriority() &&
             newData.getPriority()==data.getPriority()+1 "
    }

count (last voter really) - vote must exist and its count equal newcount, && newcount (priority) can only go up by one.

计数(真的是最后一个投票者) - 投票必须存在并且它的计数等于 newcount,&& newcount(优先级)只能增加一。

  }
}

Test script to add 10 votes by different users (for this example, id's faked, should user auth.uid in production). Count down by (i--) 10 to see validation fail.

测试脚本以添加不同用户的 10 票(对于此示例,id 是伪造的,应该在生产中使用 auth.uid)。按 (i--) 10 倒计时以查看验证失败。

<script src='https://cdn.firebase.com/v0/firebase.js'></script>
<script>
  window.fb = new Firebase('https:...vote/iss1/');
  window.fb.child('count').once('value', function (dss) {
    votes = dss.getPriority();
    for (var i=1;i<10;i++) vote(dss,i+votes);
  } );

function vote(dss,count)
{
  var user='user/zz' + count; // replace with auth.id or whatever
  window.fb.child(user).setWithPriority(count,count);
  window.fb.child('count').setWithPriority(user,count);
}
</script>

The 'risk' here is that a vote is cast, but the count not updated (haking or script failure). This is why the votes have a unique 'priority' - the script should really start by ensuring that there is no vote with priority higher than the current count, if there is it should complete that transaction before doing its own - get your clients to clean up for you :)

这里的“风险”是投票已投,但计数未更新(haking 或脚本失败)。这就是为什么投票有一个独特的“优先级”——脚本应该从确保没有优先级高于当前计数的投票开始,如果有它应该在自己做之前完成该交易——让你的客户清理为你准备:)

The count needs to be initialised with a priority before you start - forge doesn't let you do this, so a stub script is needed (before the validation is active!).

计数需要在您开始之前以优先级进行初始化 - forge 不允许您这样做,因此需要一个存根脚本(在验证处于活动状态之前!)。

回答by indvin

write a cloud function to and update the node count.

编写一个云函数并更新节点数。

// below function to get the given node count.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp(functions.config().firebase);

exports.userscount = functions.database.ref('/users/')
    .onWrite(event => {

      console.log('users number : ', event.data.numChildren());


      return event.data.ref.parent.child('count/users').set(event.data.numChildren());
    }); 

Refer :https://firebase.google.com/docs/functions/database-events

参考:https: //firebase.google.com/docs/functions/database-events

root--| |-users ( this node contains all users list) |
|-count |-userscount : (this node added dynamically by cloud function with the user count)

根--| |-users(该节点包含所有用户列表)|
|-count |-userscount : (此节点由云功能随用户数动态添加)