139

あなたは経由で子供の数を得ることができます

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

しかし、これはサーバーからそのノードのサブツリー全体をフェッチすると思います。巨大なリストの場合、RAMとレイテンシーが集中するようです。全部をフェッチせずにカウント(および/または子名のリスト)を取得する方法はありますか?

4

4 に答える 4

104

提供したコードスニペットは、実際にデータセット全体をロードしてから、クライアント側でカウントします。これは、大量のデータの場合は非常に遅くなる可能性があります。

Firebaseには現在、データを読み込まずに子をカウントする方法がありませんが、追加する予定です。

今のところ、1つの解決策は、子の数のカウンターを維持し、新しい子を追加するたびにそれを更新することです。次のように、トランザクションを使用してアイテムをカウントできます。

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は最近CloudFunctionsをリリースしました。Cloud Functionsを使用すると、独自のサーバーを作成する必要はありません。JavaScript関数を記述して、Firebaseにアップロードするだけです。Firebaseは、イベントが発生するたびに関数をトリガーする責任があります。

たとえば、賛成票を数えたい場合は、次のような構造を作成する必要があります。

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

upvotes_count次に、ノードへの新しい書き込みがあるときにを増やすためにjavascript関数を記述し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());
});

ドキュメントを読んで、 CloudFunctionsの使用を開始する方法を知ることができます。

また、投稿をカウントする別の例はここにあります: https ://github.com/firebase/functions-samples/blob/master/child-count/functions/index.js

2018年1月更新

Firebaseのドキュメント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);
});

`` `

于 2013-03-01T02:13:02.170 に答える
39

他の何人かがすでにうまく答えているので、これはゲームの少し遅いですが、私がそれをどのように実装するかを共有します。

これは、FirebaseRESTAPIがパラメータを提供するという事実に依存してい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)。

返されるキーの数をまだ計算しているため、これで問題が完全に解決するわけではなく、値が変更されても必ずしもサブスクライブできるとは限りませんが、変更を加えることなく、返されるデータのサイズを大幅に削減できます。スキーマ。

于 2016-01-22T22:46:49.043 に答える
23

カウントを保存し、検証を使用して強制します。私はこれを一緒にハッキングしました-ユニークな投票数と今後も続く数を維持するためです!。しかし、今回は私の提案をテストしました!(カット/ペーストエラーにもかかわらず!)。

ここでの「トリック」は、投票数としてノードの優先順位を使用することです。

データは次のとおりです。

投票/$issueBeingVotedOn / user / $ uniqueIdOfVoter = thisVotesCount、priority = thisVotesCountvote / $ 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()" 

ユーザーは1回だけ投票できます。&&カウントは現在のカウントより1つ大きくなければなりません。&&データ値は優先度と同じである必要があります。

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

count(実際には最後の投票者)-投票が存在する必要があり、その数はnewcountに等しく、&& newcount(優先度)は1つしか上がることができません。

  }
}

スクリプトをテストして、さまざまなユーザーによる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>

ここでの「リスク」とは、投票が行われるが、カウントが更新されないことです(ハッキングまたはスクリプトの失敗)。これが、投票に固有の「優先度」がある理由です。スクリプトは、現在のカウントよりも高い優先度の投票がないことを確認することから始めるべきです。ある場合は、独自のトランザクションを実行する前にそのトランザクションを完了する必要があります。クライアントをクリーンアップします。あなたのために:)

開始する前に、カウントを優先度で初期化する必要があります。forgeではこれを実行できないため、(検証がアクティブになる前に)スタブスクリプトが必要です。

于 2014-04-17T12:00:55.920 に答える
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

ルート--| | -users(このノードにはすべてのユーザーリストが含まれます)|
| -count | -userscount :(このノードはクラウド機能によってユーザー数とともに動的に追加されます)

于 2017-09-05T08:33:27.993 に答える