14

I searched for it, but all the answers are pretty old so maybe there is a better way. I'm trying to get a random item from a Firebase DB which looks like this:

enter image description here

I want to get a random user, that is all.

Any ideas?

Jason Aller
  • 3,541
  • 28
  • 38
  • 38
Ace
  • 469
  • 1
  • 7
  • 17
  • Doesn't look like you can do it without holding a list of users locally - https://stackoverflow.com/a/35086931/782358 – camden_kid Jul 17 '17 at 13:35
  • You can try to retrieve all the userid in the form of an array. And use Math.random to pick randomly one of the users. If you want to use this method i can show you the implementation – UmarZaii Jul 17 '17 at 13:35
  • 1
    @UmarZaii I would really apreciate that! – Ace Jul 17 '17 at 13:44
  • Please specify your question further: what is the structure of your Firebase database exactly? And what needs to be randomized exactly? Your code example is just a short HTML snippet, I'm wondering how it relates to your question exactly. – Elmar Jansen Jul 17 '17 at 14:13
  • @ElmarJansen I've edited the question to show the database structure. – camden_kid Jul 17 '17 at 15:23

5 Answers5

14

Edit: seems that this solution does not work, as "limitToFirst" and "limitToLast" are not allowed to be used together. For reference, this was the proposed (not working) solution, assuming you know the number of users:

const numberOfUsers = 15;
const randomIndex = Math.floor(Math.random() * numberOfUsers);

var ref = firebase.database().ref('companies/01/users');

ref.limitToFirst(randomIndex).limitToLast(1).once('value').then(snapshot =>
{
    var user = snapshot.val();
    // do something with the user data
});

If you don't know how many children there are (or have a children list stored somewhere else), there is no direct way to solve this problem without first receiving all children in the tree. See In Firebase, is there a way to get the number of children of a node without loading all the node data? for more info.

Elmar Jansen
  • 1,959
  • 2
  • 9
  • 10
13

I had to resolve the same problem, I added a random number from 0 to 1 to all records to finally filter by startAt and limitToFirst to 1.

Example: https://your-project-qwert.firebaseio.com/example.json?orderBy="random"&limitToFirst=1&startAt=0.84

Guillermo Jose Aiquel
  • 3,334
  • 1
  • 8
  • 4
  • 1
    This works. The currently accepted answer does not work (anymore?) since it's not allowed to use limitToFirst and limitToLast together. Also keeping a count of an array is not always scalable. his should be the accepted answer. – Nicolas Garnier Apr 28 '18 at 22:19
  • 2
    Additional note: you first have to request what is the highest random number in the list (using `orderByxxx.limitToLast(1)`) to make sure you bound your random number properly using `var rand = Math.random() * highestValue;` – Nicolas Garnier Apr 28 '18 at 22:22
  • 1
    I agree (poster of accepted answer). I tried the solution back then, don't know why it doesn't work any more. Regardless, this solution is much more elegant and useful. Does anyone know whether I can do something to help making this the accepted answer? :) – Elmar Jansen Jun 03 '18 at 16:42
  • Only the person who asked the question can change the accepted answer (I think). – tonkatata Aug 02 '20 at 20:26
  • If the user count is not large, queries similar to startAt=0.84... may not return a node. To ensure select one always, I always select node with orderByxxx.limitToLast(1) and then update the selected nodes random field in order to throw it a rondom place in the ordered list. – y.selimdogan Feb 19 '21 at 12:22
0

I have been looking for the same function, now I guess it can be done with the new released Cloud Firestore, but I'm looking for a simple solution.

btw. the neat feature of limitToFirst + limitToLast does not work, at least not in javascript (web).

The best I can come up with (if the key index "time-random" is not enough) are:

If you only need the data random once (my situation, a deck of random cards):

add a value with Math.random() and orderByChild() on that number, remove keys or use startAt() with the last used key as parameter.

var ref = firebase.database().ref('companies/01/users').push();
var randomValue = Math.random();
ref.update({ ..., 'r': randomValue });

...

var ref = firebase.database().ref('companies/01/users')
ref.orderByChild('r').limitToFirst(1).once('value').then(function(snapshot) {
  var data = snapshot.val()
  ...
  snapshot.remove()
});

If the data should be used the get a random element many times a known index is needed.

a known numbered index can be added

var ref = firebase.database().ref('companies/01/users').push();
ref.update({ ..., 'r': '0001' });

...

var ref = firebase.database().ref('companies/01/users')
ref.orderByChild('r').limitToLast(1).once('value').then(function(snapshot) {
  var totalIndex = Object.values(snapshot.val())[0].r;
});
var randomValue = Math.floor(Math.random() * totalIndex);
ref.orderByChild('r').equalTo(randomValue).once('value').then(function(snapshot) {
  var data = snapshot.val()
});
DaSe
  • 64
  • 5
0
const numberOfUsers = 15;
const randomIndex = Math.floor(Math.random() * numberOfUsers);
var ref = firebase.database().ref('companies/01/users');
ref.startAt(randomIndex).limit(numberOfUsers).once('value').then(snapshot =>
{
    var user = snapshot.val();
    // do something with the user data
});
Pascal Nitcheu
  • 667
  • 7
  • 8
-1

First you have retrieve all the userid from the firebase.

Then declare an array that stores all the userid in it. Below shows on how to store the userId.

var arr = new Array();
// or var arr = [];
arr.push('user001');
arr.push('user002');

Next you have to select randomly from one of the userId.

var item = arr[Math.floor(Math.random()*arr.length)];
// item is randomly picked userId

I'm sorry because i didn't completely show you on how the implementation works as I don't use javascript much.

Basically this is how the logic works. I hope it helps you :D

UmarZaii
  • 1,355
  • 1
  • 17
  • 26
  • 1
    The problem is this isn't scalable. It's not efficient to load the entire index, just to pick one at random. Especially when the records you're looking at are larger than the user table. – doublejosh Feb 21 '20 at 01:28