2013-03-01 9 views
94

Można uzyskać liczyć dziecko poprzezW Firebase, czy istnieje sposób na uzyskanie liczby dzieci węzła bez ładowania wszystkich danych węzła?

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

Ale wierzę, że to pobiera całą poddrzewa danego węzła z serwera. W przypadku dużych list wydaje się, że pamięć RAM i opóźnienia są intensywne. Czy istnieje sposób na uzyskanie liczby (i/lub listy nazwisk dzieci) bez pobierania całej rzeczy?

+0

dziękuję próbuję go i pracował dla mnie –

+0

kod nie może obsłużyć duży zestaw danych. Przyczyna błędu jest spowodowana przez przestrzeń sterty Java. Wciąż czekam na jakąś funkcję. –

Odpowiedz

67

Podany fragment kodu rzeczywiście ładuje cały zestaw danych, a następnie liczy go po stronie klienta, co może być bardzo powolne w przypadku dużych ilości danych.

Firebase nie ma obecnie sposobu na policzenie dzieci bez ładowania danych, ale planujemy go dodać.

Na razie jednym z rozwiązań byłoby utrzymanie licznika liczby dzieci i aktualizowanie go za każdym razem, gdy dodaje się nowe dziecko. Można użyć transakcji liczyć przedmioty, jak w tym kodzie upvodes śledzenia:

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; 
}); 

Aby uzyskać więcej informacji, zobacz https://www.firebase.com/docs/transactions.html

UPDATE: Firebase niedawno wydane Funkcje Cloud. Dzięki Cloud Functions nie trzeba tworzyć własnego serwera. Możesz po prostu napisać funkcje JavaScript i przesłać je do Firebase. Firebase będzie odpowiedzialna za uruchamianie funkcji za każdym razem, gdy wystąpi zdarzenie.

Jeśli chcesz liczyć upvotes na przykład, należy utworzyć strukturę podobną do tego:

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

A potem napisać funkcję JavaScript, żeby zwiększyć upvotes_count gdy jest nowy zapis do węzła 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()); 
}); 

Można odczytać Documentation umieć Get Started with Cloud Functions.

Również abother przykładem jest tutaj licząc posty: https://github.com/firebase/functions-samples/blob/master/child-count/functions/index.js

+54

Czy kiedykolwiek dodałeś do tego wsparcie? –

+1

Nie dodaliśmy go jeszcze. –

+16

Czy licznik po stronie klienta w transakcji jest bezpieczny? Wygląda na to, że można łatwo zhackować sztucznie zwiększać liczbę. Może to być złe dla systemów głosowania. – Soviut

21

Zapisz count as you go - i użyć go do walidacji egzekwować. Zhackowałem to razem - za utrzymanie liczby unikalnych głosów i liczby, która ciągle nadchodzi !. Ale tym razem przetestowałem moją sugestię! (niezależnie od błędów wycinania/wklejania!).

The 'trik' tutaj jest użycie węzła priorytet jako liczenia głosów ...

Dane są:

głos/$ issueBeingVotedOn/user/$ uniqueIdOfVoter = thisVotesCount, priorytet = thisVotesCount głos/$ issueBeingVotedOn/liczyć '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()" 

użytkownik może zagłosować tylko raz & & liczba musi być o jeden większa niż aktualna liczba: & & wartość danych musi być taka sama jak priorytet.

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

count (ostatni wyborca ​​naprawdę) - głosowanie musi istnieć, a jego liczba równa newcount, & & newcount (priorytet) może tylko iść w górę o jeden.

} 
} 

skrypt testowy dodać 10 głosów przez poszczególnych użytkowników (w tym przykładzie, id użytkownika sfałszowane, powinien auth.uid łatwy w produkcji). Odliczaj przez (i--) 10, aby sprawdzić, czy walidacja się nie udała.

<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> 

"Ryzyko" polega na tym, że głos jest rzucany, ale liczba nie została zaktualizowana (błąd hakerski lub skryptu). Właśnie dlatego głosy mają wyjątkowy "priorytet" - scenariusz powinien się zacząć od upewnienia się, że nie ma głosowania z priorytetem wyższym niż aktualny, jeśli jest, powinien on zakończyć tę transakcję, zanim zrobi to samodzielnie - poproś klientów, aby wyczyścili dla ciebie :)

Licznik musi zostać zainicjowany z priorytetem przed uruchomieniem - forge nie pozwala tego zrobić, więc potrzebny jest skrypt pośredniczący (przed aktywacją walidacji!).

+0

To jest niesamowite !!! Co dzieje się w przypadku konfliktów? Tak, dwie osoby głosują w tym samym czasie? Najlepiej, aby automatycznie rozwiązać to, zamiast po prostu odrzucić jeden z ich głosy ... może głosowanie w transakcji? – josh

+0

Witam Josh, logicznie rzecz biorąc, prawdziwy głos może się nie powieść, jeśli poprzedni głos został oddany, ale nie został zaktualizowany (jeszcze). "Po prostu wykonuj całkowitą aktualizację dla poprzednich głosujących w każdym przypadku (za każdym razem) - jeśli nie była potrzebna, to co?", a następnie ta aktualizacja głosów.Dopóki głosowanie nie zadziała. Jeśli twoja "całkowita" aktualizacja nie powiedzie się, następny wyborca ​​ją naprawi, więc znowu - co z tego? – pperrin

+0

Naprawdę mam ochotę po prostu powiedzieć, że węzeł "count" powinien być węzłem "ostatni poprzedni głos" - więc każdy głosujący/klient aktualizuje/naprawia/naprawia ten węzeł/wartość, a następnie dodaje swój własny głos (pozwalając na kolejną aktualizację głosowania) suma uwzględniająca "to" głosowanie). - Jeśli dostaniesz mój dryf ... – pperrin

-6

Doceniam, że jest to 2 lata od otwartego pytania, ale jako pierwszy wynik w Google pomyślałem, że będę aktualizować, ponieważ obecnie szukam sposobu, aby uzyskać liczbę obiektów dzieci. Można to zrobić z

DataSnapshot.numChildren() metoda pod warunkiem, więcej szczegółów można znaleźć tutaj - Firebase Website

+12

Jest to podejście zaproponowane przez OP - problem polega na tym, że ładuje całe drzewo z Firebase i liczy je po stronie klienta, co powoduje koszty transferu danych. –

20

To jest trochę późno w grze, jak kilka innych już odpowiedział ładnie, ale będę dzielić jak mogę to zaimplementować.

Wynika to z faktu, że Firebase REST API oferuje parametr .

Załóżmy, że masz post obiekt, a każdy z nich może mieć szereg comments:

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

Na pewno nie chcesz, aby pobrać wszystkie komentarze, po prostu liczbę komentarzy.

Zakładając, że masz klucz do wpisu, możesz wysłać żądanie GET do https://yourapp.firebaseio.com/posts/[the post key]/comments?shallow=true.

Spowoduje to przywrócenie obiektu par klucz-wartość, gdzie każdy klucz jest kluczem komentarz i jego wartość jest true:

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

Wielkość tej reakcji jest znacznie mniejsza niż zainteresowanie równoważne dane , a teraz możesz obliczyć liczbę kluczy w odpowiedzi, aby znaleźć swoją wartość (np. commentCount = Object.keys(result).length).

Może to nie w pełni rozwiązać problem, ponieważ wciąż oblicza się liczbę zwróconych kluczy i nie można koniecznie zasubskrybować wartości w miarę jej zmiany, ale znacznie zmniejsza to rozmiar zwracanych danych bez konieczności wszelkie zmiany w twoim schemacie.

+0

Może to być zaakceptowana odpowiedź, ponieważ shallow = true jest nowym dodatkiem od czasu poprzednich odpowiedzi. Nie miałem czasu samemu się temu przyjrzeć, więc poczekam kilka dni, aby zobaczyć, co ludzie sądzą ... – josh

+0

Płytka jest prawdopodobnie najlepszą opcją na razie, ale nie jest zwracana z kompresją i może stać się dość powolna, a doświadczenie dla dużych zestawy danych – Mbrevda

+0

Jeśli klucze komentarza nie mają wartości boolowskich, ale zamiast tego mają elementy potomne, czy nadal zwracają pary klucz-wartość kluczy? – alltej

4

Napisz funkcję chmury i zaktualizuj liczbę węzłów.

// 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()); 
    }); 

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

root-- | | -Users (ten węzeł zawiera listę wszystkich użytkowników) |
| -count | -userscount: (węzeł dodany dynamicznie przez funkcję chmurze z liczbą użytkowników)

Powiązane problemy