В Firebase есть ли способ получить число дочерних элементов node без загрузки всех данных node?

Вы можете получить счетчик ребенка через

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

Но я считаю, что это извлекает все поддерево этого node с сервера. Для огромных списков это кажется оперативной памятью и латентностью. Есть ли способ получить счет (и/или список дочерних имен), не извлекая все это?

Ответ 1

Приведенный вами фрагмент кода действительно загружает весь набор данных и затем считает их на стороне клиента, что может быть очень медленным для больших объемов данных.

В настоящее время 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/transactions.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

Ответ 2

Это немного поздно в игре, так как несколько других уже ответили хорошо, но я поделюсь, как я мог бы это реализовать.

Это зависит от того, что 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).

Это может не полностью решить вашу проблему, так как вы по-прежнему рассчитываете количество возвращаемых ключей, и вы не можете обязательно подписаться на значение при его изменении, но это значительно уменьшает размер возвращаемых данных, не требуя каких-либо изменений в вашем схемы.

Ответ 3

Сохраните счет, когда вы идете, и используйте валидацию для его принудительного применения. Я взломал это вместе - за счет подсчета уникальных голосов и подсчетов, которые продолжают расти! Но на этот раз я опробовал свое предложение! (несмотря на ошибки вырезания/вставки!).

"Трюк" здесь состоит в том, чтобы использовать приоритет node как подсчет голосов...

Данные:

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 (priority) может увеличиваться только на один.

  }
}

Тест script, чтобы добавить 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>

"Риск" здесь заключается в том, что голосование проводится, но счет не обновляется (провал или сбой script). Вот почему голоса имеют уникальный "приоритет" - script должен действительно начинаться с того, что нет голоса с приоритетом выше текущего счета, если он должен завершить эту транзакцию, прежде чем делать свое дело - получить своих клиентов очистить для вас:)

Подсчет должен быть инициализирован с приоритетом, прежде чем вы начнете - forge не позволяет вам это делать, поэтому необходим заглушка script (до того, как валидация будет активна!).

Ответ 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 | -users count: (этот узел динамически добавляется с помощью облачной функции с количеством пользователей)

Ответ 5

Я ценю, что это 2 года от открытого вопроса, но в качестве первого результата Google я думал, что обновляюсь, поскольку в настоящее время я ищу способ получить количество объектов для детей. Это можно сделать с помощью

Предоставлен метод DataSnapshot.numChildren(), более подробную информацию можно найти здесь - Firebase Website