Лучшая практика Firebase для подсчета списков [duplicate]

Это обсуждается в учебнике Oracle Определение и запуск потока :

Какую из этих идиом вы должны использовать? Первая идиома, которая использует объект Runnable, является более общей, поскольку объект Runnable может подклассифицировать класс, отличный от Thread. Вторая идиома проста в использовании в простых приложениях, но ограничена тем, что ваш класс задачи должен быть потомком Thread. В этом уроке основное внимание уделяется первому подходу, который отделяет задачу Runnable от объекта Thread, выполняющего задачу. Этот подход не только более гибкий, но применим к API-интерфейсам управления потоками высокого уровня, рассмотренным позже.

Другими словами, реализация Runnable будет работать в сценариях, где ваш класс расширяется класс, отличный от Thread. Java не поддерживает множественное наследование. Кроме того, расширение Thread не будет возможно при использовании некоторых высокоуровневых API управления потоками. Единственный сценарий, когда расширение Thread предпочтительнее, - это небольшое приложение, которое в будущем не будет обновляться. Практически лучше реализовать Runnable, поскольку он более гибкий по мере роста вашего проекта. Изменение дизайна не окажет большого влияния, поскольку вы можете реализовать множество интерфейсов в java, но только расширить один класс.

103
задан TomStr 23 August 2016 в 16:30
поделиться

5 ответов

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

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

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

Вы можете прочитать Documentation , чтобы знать, как Начните работу с облачными функциями .

Кроме того, здесь приведен пример других учетных записей: https://github.com/firebase/functions-samples/blob/master/ ребенок-счет / функция / index.js

77
ответ дан Chance Smith 20 August 2018 в 10:11
поделиться
  • 1
    Вы когда-нибудь добавляли поддержку для этого? – Jim Cooper 23 February 2014 в 03:49
  • 2
    Является ли клиентский счетчик транзакцией безопасным? Кажется, что его можно легко взломать, чтобы искусственно увеличить количество очков. Это может быть плохо для систем голосования. – Soviut 7 April 2014 в 07:10
  • 3
    ++ было бы очень приятно получить счет без затрат на перевод – Jared Forsyth 9 August 2014 в 22:41
  • 4
    Было ли это добавлено? – Eliezer 5 June 2015 в 03:57
  • 5
    Любые новости об этой дорожной карте? благодаря – Pandaiolo 27 July 2015 в 15:30

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

Это зависит от того, что Firebase REST API предлагает параметр shallow=true.

Предположим, что у вас есть объект post, и каждый из них может иметь номер comments:

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

Вы, очевидно, не хотите получать все комментарии, просто количество комментариев.

Предполагая, что у вас есть ключ для сообщения, вы можете отправить запрос GET на https://yourapp.firebaseio.com/posts/[the post key]/comments?shallow=true.

Это вернет объект key- пары значений, где каждый ключ является ключом комментария, а его значение - true:

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

Размер этого ответа намного меньше, чем запрос эквивалентных данных, и теперь вы можете рассчитать количество ключей в ответе, чтобы найти ваше значение (например, commentCount = Object.keys(result).length).

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

23
ответ дан emjames 20 August 2018 в 10:11
поделиться
  • 1
    Мог бы сделать это принятым ответом, так как мелкий = истинный - новое дополнение с предыдущих ответов. Не успел заглянуть в нее сам, так что подождем несколько дней, чтобы посмотреть, что думают люди ... – josh 26 January 2016 в 20:08
  • 2
    В настоящее время Shallow - лучший вариант, но он не возвращается с сжатием и может стать довольно медленным и иметь опыт работы с большими наборами данных – Mbrevda 24 June 2016 в 09:36
  • 3
    Если ключи комментариев не имеют логических значений, но вместо этого имеют дочерние элементы, он все равно возвращает пары ключей-значений ключей? – alltej 27 February 2017 в 13:18
  • 4
    Вы можете быть осторожны с использованием REST API: startupsventurecapital.com/… – Remi Sture 8 August 2017 в 07:28
  • 5
    Чтобы указать, что вы должны добавить .json в конец URL-адреса, например: https://yourapp.firebaseio.com/posts/comments.json?shallow=true – Osama Xäwãñz 12 August 2017 в 15:37

записать функцию облака и обновить количество узлов.

// 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-- | | -sers (этот узел содержит список всех пользователей) | | -count | -userscount: (этот узел динамически добавлен функцией облака с подсчетом пользователя)

5
ответ дан indvin 20 August 2018 в 10:11
поделиться

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

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

-6
ответ дан Jon D 20 August 2018 в 10:11
поделиться
  • 1
    На самом деле это подход, предложенный OP - проблема заключается в том, что он загружает все дерево из Firebase и считает его клиентской стороной, что приводит к расходам на передачу данных. – Matt Lyons 8 December 2015 в 22:53

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

Здесь «трюк» должен использовать узел priority в качестве количества голосов ...

данные:

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

пользователь может голосовать только один раз & amp; & amp; & amp; счет должен быть выше, чем текущий счетчик & amp; & amp; значение данных должно быть таким же, как и приоритет.

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

count (последний избиратель действительно) - голос должен существовать и его счет равен newcount, & amp; & amp; newcount (priority) может подниматься только на один.

  }
}

Тестовый скрипт для добавления 10 голосов разными пользователями (для этого примера фальшивка id должна быть выполнена пользователем auth.uid в процессе производства). Counting by (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 не позволяет вам это делать, поэтому необходим скрипт-заглушка (до того, как валидация будет активна!).

22
ответ дан pperrin 20 August 2018 в 10:11
поделиться
  • 1
    Это круто!!! Что же происходит с конфликтами? То есть, два человека голосуют одновременно? В идеале вы хотели бы автоматически разрешить это, вместо того, чтобы просто отказаться от одного из своих голосов ... возможно, сделать голосование в транзакции? – josh 17 April 2014 в 22:06
  • 2
    Привет, Джош, логически подлинное голосование может потерпеть неудачу, только если был выбран предыдущий голос, но общее не обновлено (пока). Мой второй-последний пара охватывает это: я бы просто сделал общее обновление для предыдущих голосов избирателей в любом случае (каждый раз) - если это не было необходимо, так что? и затем это обновление голосов. Пока голосование работает нормально. Если ваше «общее» обновление не удастся, следующий избиратель исправит его, так что еще раз - ну и что? – pperrin 18 April 2014 в 00:30
  • 3
    Я действительно испытываю соблазн просто сказать, что узел «count» должен быть узлом «последнего предыдущего голосования», поэтому каждый избиратель / клиент обновляет / исправляет / исправляет этот узел / значение, а затем добавляет свой собственный голос - (позволяя следующему избирателю обновить всего, чтобы включить «этот» голос). - Если ты получишь мой дрейф ... – pperrin 18 April 2014 в 00:39
Другие вопросы по тегам:

Похожие вопросы: