Чи є у Firebase спосіб отримати кількість дітей вузла, не завантажуючи всі дані вузла?


132

Ви можете отримати рахунок дитини через

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

Але я вважаю, що це отримує все під-дерево цього вузла з сервера. Для величезних списків це здається оперативною пам’яттю та затримкою. Чи існує спосіб отримання підрахунку (та / або списку імен дітей) без отримання цілої речі?


велике спасибі, я пробую це, і це спрацювало на мене
Ахмед Махмуд

Ваш код не може обробляти великий набір даних. Я отримав причину помилок у купі Java-простору. Я ще чекаю якоїсь функції.
Panupong Kongarn

Відповіді:


98

Розроблений фрагмент коду дійсно завантажує весь набір даних, а потім підраховує його на стороні клієнта, що може бути дуже повільним для великих обсягів даних.

На даний момент Firebase не має можливості рахувати дітей без завантаження даних, але ми плануємо їх додавати.

Наразі одним із рішень було б підтримувати лічильник кількості дітей та оновлювати його щоразу, коли ви додаєте нову дитину. Ви можете використовувати транзакцію для підрахунку елементів, як-от у цьому відстеженні коду:

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/transaction.html

ОНОВЛЕННЯ: Firebase недавно випустила хмарні функції. За допомогою хмарних функцій вам не потрібно створювати власний сервер. Ви можете просто написати функції JavaScript і завантажити їх у Firebase. Firebase буде нести відповідальність за запуск функцій кожного разу, коли трапляється подія.

Якщо ви хочете, наприклад, порахувати додаткові оцінки, вам слід створити структуру, подібну до цієї:

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

Ви можете прочитати Документацію, щоб знати, як розпочати роботу з функціями хмари .

Також ще один приклад підрахунку публікацій: https://github.com/firebase/functions-samples/blob/master/child-count/functions/index.js

Оновлення січня 2018 року

Документи вогневої бази змінилися, замість цього 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);
});

`` `


74
Ви коли-небудь додавали підтримку для цього?
Джим Купер

20
Чи захищений клієнт лічильник транзакцій? Здається, його можна легко зламати, щоб штучно збільшити кількість. Це може бути погано для систем голосування.
Радянський

16
++ було б дуже приємно зарахувати рахунок, не несучи витрат на трансфер
Jared Forsyth

27
Це колись додано?
Eliezer

25
Будь-які новини щодо цієї дорожньої карти? Спасибі
Пандайоло

37

Це трохи пізно в грі, оскільки декілька інших вже відповіли чудово, але я поділюся, як я можу це реалізувати.

Це залежить від того, що API REST Firebase пропонує 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).

Це може не повністю вирішити вашу проблему, оскільки ви все ще обчислюєте кількість повернених ключів, і ви не можете обов'язково підписатися на значення, оскільки воно змінюється, але це значно зменшує розмір повернених даних, не вимагаючи жодних змін у вашому схема.


Ви можете зробити це прийнятою відповіддю, оскільки мілка = істина є новим доповненням з попередніх відповідей. Я не встиг сам заглянути в це, тому зачекаю кілька днів, щоб побачити, що думають люди ...
josh

1
Дрібні - це, мабуть, найкращий варіант на даний момент, але він не повертається стисненням і може стати досить повільним та досвід для великих наборів даних
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": {
  ".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 "
    }

підрахунок (насправді останній виборця) - голосування повинно існувати, а його кількість рівний новому рахунку, а & newcountcount (пріоритет) може збільшитися лише на один.

  }
}

Тестовий сценарій, щоб додати 10 голосів різних користувачів (для цього прикладу, підроблений ідентифікатор, повинен користувач 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 не дозволяє цього робити, тому потрібен сценарій заглушки (до того, як перевірка буде активна!).


Це круто!!! Що ж відбувається на конфліктах? Тобто двоє людей голосують одночасно? В ідеалі ви хочете автоматично вирішити це, замість того, щоб просто відкинути один з їхніх голосів ... можливо, ви можете голосувати за транзакцію?
Джош

Привіт Джош, логічно справжнє голосування може бути невдалим лише у тому випадку, якщо був поданий попередній голос, але загальна кількість не оновлена ​​(поки що). Мій другий до останнього пункту стосується цього - я б просто все-таки оновив попереднє голосування виборців (якщо це не було) - якщо це не було потрібно, то що? а потім це голосування оновлюється. Поки голосування працює нормально. Якщо ваше "загальне" оновлення не вдасться, наступний виборець це виправить, тож знову - так що?
pperrin

Я дуже спокушаюсь сказати, що вузол «підрахунку» повинен бути вузлом «останнього попереднього голосування» - тому кожен виборець / клієнт оновлює / виправляє / відновлює цей вузол / значення, а потім додає власний голос - (дозволяючи наступному виборцеві оновити оновлення всього, щоб включити голосування "цей"). - Якщо ви отримаєте мій дрейф ...
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

корінь-- | | -користувачі (цей вузол містить усі списки користувачів) |
| -count | -userscount: (цей вузол динамічно додається хмарною функцією з кількістю користувачів)

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.