Firebase是否按提交顺序返回数据?Android端如何实现随机查询用户列表?
问题解答
1. Firebase默认查询规则说明
Firebase Realtime Database 未提供随机返回结果的能力,默认返回子节点的顺序为子节点key的字典升序。若你使用Firebase默认push()方法生成用户ID,这类ID内嵌时间戳信息,越早注册的用户ID字典序越小,默认查询时会优先返回更早注册的用户,完全无法保证所有用户的展示机会均等。
2. Android端实现完全随机查询的方案
你要求完全随机的返回结果,优先推荐以下适配你现有业务的实现方案:
方案1:本地随机排序(适用于异性用户量级<1w的场景)
该方案可实现100%完全随机,实现逻辑简单,适配你现有过滤规则:
先全量拉取对应性别分类下的所有用户节点,在本地完成过滤后将符合条件的用户列表随机洗牌,再按洗牌后的顺序填充展示列表即可,参考代码如下:
if(mAuth.getCurrentUser().isEmailVerified()) { FirebaseDatabase.getInstance().getReference().child("Users").child(UserSex).child(currentUserID).child("isVerified").setValue(true); } DatabaseReference oppositeSexDB= FirebaseDatabase.getInstance().getReference().child("Users").child(OppositeUserSex); // 单次拉取全量数据做本地过滤随机 oppositeSexDB.addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(@NonNull DataSnapshot snapshot) { List<DataSnapshot> validUserSnaps = new ArrayList<>(); for (DataSnapshot userSnap : snapshot.getChildren()) { // 复用原有过滤逻辑 if(!userSnap.child("Selection").child("Nah").hasChild(currentUserID) && userSnap.child("Url").exists() && userSnap.child("isVerified").exists()) { validUserSnaps.add(userSnap); } } // 本地随机打乱 Collections.shuffle(validUserSnaps); // 填充列表 items.clear(); for (DataSnapshot validSnap : validUserSnaps) { items.add(new ItemModel( validSnap.child("Url").getValue().toString(), validSnap.child("Name").getValue().toString(), "", "", validSnap.getKey() )); } adapter.notifyDataSetChanged(); } @Override public void onCancelled(@NonNull DatabaseError error) { // 自行添加异常处理逻辑 } });
方案2:预存随机字段(适用于异性用户量级较大的场景)
如果全量拉取数据带宽成本过高,可给每个用户节点新增一个randomSeed字段,值为0~1之间的随机浮点数,该方案的排序依据是动态更新的随机值,不属于固定业务字段排序,完全可以满足随机展示需求,每次查询逻辑如下:
- 本地生成一个0~1的随机数
randomVal,优先执行orderByChild("randomSeed").startAt(randomVal).limitToFirst(需要拉取的数量)拉取数据 - 若返回结果不足,再执行
orderByChild("randomSeed").endAt(randomVal).limitToLast(剩余需要补的数量)补充数据
可定期给所有用户更新randomSeed值,避免展示位置固定。
内容的提问来源于stack exchange,提问作者CS Learner
相关产品推荐
相关产品推荐

