从Java中的Firebase实时数据库中选择随机条目

从Java中的Firebase实时数据库中选择随机条目,java,android,firebase,firebase-realtime-database,Java,Android,Firebase,Firebase Realtime Database,我正在为Android开发一个应用程序,其中包括上传和下载图像到服务器。我正在使用Firebase进行此操作。所有图像都使用图像哈希作为文件名存储在Firebase存储器中。我还维护了一个实时数据库,其中存储了一些有关图片的信息。我需要从存储器中随机选择一张图片,所以我决定从数据库中随机选择一个条目。我在上面找到了答案,如您所见,int是用Javascript编写的,这表明以下代码: const numberOfUsers = 15; const randomIndex = Math.floor

我正在为Android开发一个应用程序,其中包括上传和下载图像到服务器。我正在使用Firebase进行此操作。所有图像都使用图像哈希作为文件名存储在Firebase存储器中。我还维护了一个实时数据库,其中存储了一些有关图片的信息。我需要从存储器中随机选择一张图片,所以我决定从数据库中随机选择一个条目。我在上面找到了答案,如您所见,int是用Javascript编写的,这表明以下代码:

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
});
但是当我尝试用Java构建类似的查询时

imgref.limitToFirst(random + 1).limitToLast(1).addValueEventListener(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            randomHash = dataSnapshot.getKey();
            Log.e("get random name: ", randomHash);
        }

        @Override
        public void onCancelled(DatabaseError databaseError) {

        }
    });
我收到一个错误

无法使用以前设置的限制在查询中调用limitToLast

所以很明显,我不能在一个查询中使用limitToFirst和LimitToLast。所以我的问题是:

是否可以同时使用limitToFirst和limitToLast来使用这种获取随机条目的方法

是否有其他方法可以从Firebase实时数据库中获取随机条目,而无需下载整个数据库或对其进行迭代?据我所知,迭代效率低下,如果我错了,请解释

如果无法从应用程序内部执行此操作,是否有其他方法,例如,使用Firebase云功能


您需要知道您的模型如何获得随机密钥。如果它是1,2,3,4,5个ID,你可以像现在一样使用它,这样你就可以比较它了。
最好的方法是将所有键值存储在一个数组中,根据数组大小选择一个随机数,然后选择随机数的索引。他们使用类似答案dataSnapshot.getKey中的代码

如果您不反对在数据中添加额外的子项,那么您有几个选择

您可以使用事务对添加的每个项目进行编号,然后使用带有startAtrandom.limitToFirst1的随机数。 如果要避免该事务,可以向每个imgref节点写入随机long。然后您可以尝试使用新生成的随机数据进行查询,如下所示:

ref.orderByChild("randomLong").startAt(newRandomLong).limitToFirst(1).addListenerForSingleValueEvent(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        if(dataSnapshot.getChildrenCount() > 0){
            for(DataSnapshot snap : dataSnapshot.getChildren()){
                //Do something with your random snapshot
            }
        }else
        {
         /*
         Handle case where the new random Long is after the range 
         currently in the database
         ref.orderByChild("randomLong").endAt(random).limitToLast(1)
         */
        }
    }

    @Override
    public void onCancelled(DatabaseError databaseError) {

    }
});
请注意,2将根据值之间的随机范围向值添加随机权重。这种效果在较大的列表上应该不太明显,但如果您需要一个均匀的分布,您可能希望使用选项1


如果您不能更改当前的数据结构,那么我不确定您是否可以像Alex的回答中那样迭代集合。

可能的重复,请检查重复,看看如何进行。@AlexMamo,据我所知,该解决方案会迭代整个表,这是低效的。如果我错了,请纠正我,因为我不是如何迭代数据库的专家works@AlexMamo遍历条目是否会从条目中下载数据?在引用中添加侦听器时,您正在加载侦听器指向的整个对象。在上面的链接中,您正在获取该节点下的子节点,使用getChildren方法进行迭代并从中选择一个随机结果。我同意添加一个新的子节点,但我认为您的解决方案存在一些问题。首先,如果两个条目获得相同的随机ID,将永远不会选择其中一个。其次,例如,如果条目具有以下ID:100、110,则具有100值的条目具有更高的被选择概率,因为从0到100的任何随机数都将选择第一个数字,虽然只有101到110之间的数字会选择第二个,但我刚刚编辑了我的解决方案,以提及您提到的第二个问题。第一个问题不太可能是使用long时出现的问题,因为在列表变大之前,碰撞的可能性很小。