您可以通过
获取子女数firebase_node.once('value', function(snapshot) { alert('Count: ' + snapshot.numChildren()); });
但我相信这会从服务器中获取该节点的整个子树。对于巨大的列表,这似乎是RAM和延迟密集型。有没有办法获取计数(和/或子名称列表)而不取出整个事物?
答案 0 :(得分:88)
您提供的代码段确实会加载整个数据集,然后将其计入客户端,这对于大量数据来说可能非常慢。
Firebase目前无法在不加载数据的情况下统计子项,但我们计划添加它。
目前,一种解决方案是维护子女数量的计数器,并在每次添加新孩子时更新它。您可以使用事务来计算项目,例如此代码跟踪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;
});
有关详细信息,请参阅https://www.firebase.com/docs/transactions.html
<强>更新强> Firebase最近发布了Cloud Functions。使用云功能,您无需创建自己的服务器。您只需编写JavaScript函数并将其上传到Firebase即可。 Firebase将负责在事件发生时触发功能。
例如,如果你想计算upvotes,你应该创建一个类似于这个的结构:
{
"posts" : {
"-JRHTHaIs-jNPLXOQivY" : {
"upvotes_count":5,
"upvotes" : {
"userX" : true,
"userY" : true,
"userZ" : true,
...
}
}
}
}
然后编写一个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());
});
您可以阅读Documentation了解如何Get Started with Cloud Functions。
此外,另一个计算帖子的例子如下: https://github.com/firebase/functions-samples/blob/master/child-count/functions/index.js
firebase docs已更改,而不是event
我们现在有change
和context
。
给出的示例抛出一个错误,抱怨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);
});
```
答案 1 :(得分:24)
这在游戏中有点晚了,因为其他几个人已经很好地回答了,但我将分享如何实现它。
这取决于Firebase REST API提供shallow=true
参数的事实。
假设您有一个post
对象,每个对象可以有comments
个数:
{
"posts": {
"$postKey": {
"comments": {
...
}
}
}
}
您显然不想获取所有评论,只需要提取评论数量。
假设您有帖子的密钥,您可以发送GET
个请求
https://yourapp.firebaseio.com/posts/[the post key]/comments?shallow=true
。
这将返回一个键值对的对象,其中每个键是注释的键,其值为true
:
{
"comment1key": true,
"comment2key": true,
...,
"comment9999key": true
}
此响应的大小远小于请求等效数据,现在您可以计算响应中的键数以查找您的值(例如commentCount = Object.keys(result).length
)。
这可能无法完全解决您的问题,因为您仍在计算返回的密钥数,并且您不一定在更改时订阅该值,但它确实大大减少了返回数据的大小而不需要任何更改您的架构。
答案 2 :(得分:21)
随时保存计数 - 并使用验证来强制执行。我一起攻击了这个 - 为了保持一个独特的选票数和不断上升的数量!但这次我测试了我的建议! (尽管有剪切/粘贴错误!)。
此处的'技巧'是使用节点 priority 作为投票计数......
数据是:
vote / $ issueBeingVotedOn / user / $ uniqueIdOfVoter = thisVotesCount,priority = thisVotesCount vote / $ 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()"
用户只能投票一次&amp;&amp;数量必须高于当前数量&amp;&amp;数据值必须与优先级相同。
}
}
,"count" : {
".validate" : "data.parent().child(newData.val()).val()==newData.getPriority() &&
newData.getPriority()==data.getPriority()+1 "
}
计数(真正的最后一个选民) - 投票必须存在并且其计数等于newcount,&amp;&amp; newcount(优先级)只能上升一个。
}
}
测试脚本以便由不同用户添加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>
此处的'风险'是投票,但计数未更新(黑客或脚本失败)。这就是为什么投票具有独特的“优先级” - 脚本应该首先确保没有优先级高于当前计数的投票,如果它应该在完成该事务之前完成该事务 - 让客户清理为你服务:))
在开始之前需要使用优先级初始化计数 - 伪造不允许您这样做,因此需要存根脚本(在验证激活之前!)。
答案 3 :(得分:4)
将云功能写入并更新节点数。
// 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());
});
参考:https://firebase.google.com/docs/functions/database-events
root-- |
| -users(此节点包含所有用户列表)
|
| -count
| -userscount:
(此节点由云功能和用户计数动态添加)
答案 4 :(得分:-6)
我很欣赏这是从开放问题开始的2年,但是作为它的第一个谷歌结果,我认为我会更新,因为我正在寻找一种方法来获取对象的计数。这可以通过
完成提供了DataSnapshot.numChildren()方法,可在此处找到更多详细信息 - Firebase Website