Firebase에서 모든 노드 데이터를로드하지 않고 노드의 자식 수를 얻는 방법이 있습니까?


132

자녀 수를 통해 알 수 있습니다

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

그러나 이것이 서버에서 해당 노드의 전체 하위 트리를 가져옵니다. 거대한 목록의 경우 RAM과 대기 시간이 많이 소요되는 것 같습니다. 모든 것을 가져 오지 않고 카운트 (및 / 또는 자식 이름 목록)를 얻는 방법이 있습니까?


고마워 내가 그것을 시도하고 그것은 나를 위해 일했다
Ahmed Mahmoud

코드가 큰 데이터 세트를 처리 할 수 ​​없습니다. Java 힙 공간으로 인해 오류가 발생했습니다. 여전히 일부 기능을 기다리고 있습니다.
Panupong Kongarn

답변:


98

당신이 준 코드 스 니펫은 실제로 전체 데이터 세트를로드 한 다음 클라이언트 측에서 계산합니다. 이는 대량의 데이터에 대해 매우 느릴 수 있습니다.

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를 출시했습니다. Cloud Functions를 사용하면 자체 서버를 만들 필요가 없습니다. JavaScript 함수를 작성하여 Firebase에 업로드하면됩니다. Firebase는 이벤트가 발생할 때마다 기능을 트리거합니다.

예를 들어 투표를 계산하려면 다음과 유사한 구조를 만들어야합니다.

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

그런 다음 노드에 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());
});

당신이 읽을 수있는 문서를 하는 방법을 알고 클라우드 기능 시작하기 .

또한 게시물 수를 계산하는 또 다른 예는 다음과 같습니다. https://github.com/firebase/functions-samples/blob/master/child-count/functions/index.js

2018 년 1 월 업데이트

중포 기지 문서는 그래서 대신 변경 event우리가 지금 가지고 changecontext.

주어진 예제 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);
});

```


74
이것에 대한 지원을 추가 한 적이 있습니까?
Jim Cooper

20
트랜잭션의 클라이언트 측 카운터는 안전합니까? 인위적으로 수를 늘리기 위해 쉽게 해킹 될 수있는 것 같습니다. 투표 시스템에는 좋지 않을 수 있습니다.
Soviut

16
++는 전송 비용을 들이지 않고 카운트를 얻기 위해 정말 좋은 것
제라드 포 시스

27
이것도 추가 된 적이 있습니까?
Eliezer

25
이 기능 로드맵에 대한 뉴스가 있습니까? 감사합니다
Pandaiolo

38

다른 사람들이 이미 잘 대답 했으므로 게임에서 약간 늦었지만 구현 방법을 알려 드리겠습니다.

이는 Firebase REST APIshallow=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).

반환 된 키 수를 계산하고 있기 때문에 문제를 완전히 해결할 수는 없으며 변경 될 때 값을 구독 할 필요는 없지만 반환 된 데이터의 크기를 크게 변경하지 않아도됩니다. 개요.


shallow = true는 이전 답변 이후의 새로운 추가 사항이므로 허용되는 답변으로 만들 수 있습니다. 스스로 조사 할 시간이 없었으므로 사람들이 어떻게 생각하는지 며칠 기다릴 것입니다.
josh

1
Shallow는 아마도 현재로서는 최선의 선택이지만 압축과 함께 반환되지 않으며 상당히 느려져서 큰 데이터 세트에 대한 경험이 될 수 있습니다.
Mbrevda

주석 키에 부울 값이없고 대신 자식이있는 경우 키-값 쌍의 키를 계속 반환합니까?
alltej

1
REST API를 사용하여 조심해야 할 수도 있습니다 : startupsventurecapital.com/…
Remi Sture

3
.json예를 들어 다음과 같이 URL 끝에 추가 해야합니다.https://yourapp.firebaseio.com/posts/comments.json?shallow=true
Osama Xäwãñz

22

카운트를 저장 한 후 유효성을 검사하여 적용하십시오. 나는 독특한 투표와 카운트를 계속 유지하기 위해 이것을 해킹했습니다. 그러나 이번에는 제안을 테스트했습니다! (잘라 내기 / 붙여 넣기 오류에도 불구하고!).

여기서 '트릭'은 노드 우선 순위 를 투표 수로 사용하는 것입니다.

데이터는 다음과 같습니다

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()" 

사용자는 한 번만 투표 할 수 있으며 && 개수는 현재 개수보다 높고 데이터 값은 우선 순위와 동일해야합니다.

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

count (마지막 유권자 수)-투표가 존재해야하며 그 수는 newcount와 같으며 && newcount (우선 순위)는 1 씩만 올라갈 수 있습니다.

  }
}

다른 사용자가 10 표를 추가하는 테스트 스크립트 유효성 검사에 실패하면 (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>

여기서 '위험'은 투표가 진행되었지만 카운트가 업데이트되지 않은 것입니다 (학킹 또는 스크립트 실패). 그렇기 때문에 투표에 고유 한 '우선 순위'가 있습니다. 스크립트는 실제로 현재 순위보다 우선 순위가 높은 투표가 없는지 확인하여 시작해야합니다. 당신을 위해 :)

시작하기 전에 우선 순위로 카운트를 초기화해야합니다. 위조를 통해이를 수행 할 수 없으므로 유효성 검사가 활성화되기 전에 스텁 스크립트가 필요합니다.


대단해 !!! 그래도 충돌은 어떻게됩니까? 즉, 두 사람이 동시에 투표합니까? 이상적으로는 투표 중 하나를 버리는 대신 자동으로 해결하고 싶을 것입니다 ... 거래에서 투표를 할 수 있습니까?
josh

안녕하세요, Josh, 논리적으로 진정한 투표는 이전 투표가 제출되었지만 총계가 아직 업데이트되지 않은 경우에만 실패 할 수 있습니다. 마지막 두 번째 단락은 이전 유권자들의 투표를 위해 (매번) 전체 업데이트를 수행하고 싶습니다. 필요하지 않은 경우 어떻게해야합니까? 그런 다음 업데이트에 투표합니다. 투표가 잘되는 한. 귀하의 '전체'업데이트가 실패하면 다음 유권자가 수정합니다. 다시 무엇을?
pperrin

나는 'count'노드가 '마지막 이전 투표'노드 여야한다고 말하고 싶습니다. 따라서 각 유권자 / 클라이언트는 해당 노드 / 값을 업데이트 / 수정 / 수리 한 다음 자체 투표를 추가합니다-(다음 유권자에게 'this'투표를 포함하는 합계). -당신이 내 드리프트를 얻는다면 ...
pperrin

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 : (이 노드는 사용자 수와 함께 클라우드 기능에 의해 동적으로 추가됨)

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.