【问题标题】:How can I change the firestore recycler order by a code variable and not a cloud variable (query)?如何通过代码变量而不是云变量(查询)更改 Firestore 回收器顺序?
【发布时间】:2025-12-10 17:25:01
【问题描述】:

我有一个插入到 Firestore 回收器中的对象列表,我需要按当前用户的距离和用户与对象的距离对它们进行排序,我能够通过获取当前用户来计算它们之间的距离用户的位置并拉出相关对象的发布者的位置,它返回它们之间的距离(以米为单位),我想使用它作为参数根据获得的值对数据进行排序,但是,唯一的方法订购获得的数据是使用这个文件firestore queries Firestore

但这花费了我很多钱而且不是很有效,我可以做些什么来根据我创建的这个局部距离变量来更改列出的对象的顺序吗?

例子

 if(locationResult != null && locationResult.getLocations().size() > 0){

    int latestLocationIndex = locationResult.getLocations().size() - 1;
    latitudeUser = locationResult.getLocations().get(latestLocationIndex).getLatitude();
    longitudeUser = locationResult.getLocations().get(latestLocationIndex).getLongitude();
    localizacaoUser.setLatitude(latitudeUser); // Latitude do usuário adquirida
    localizacaoUser.setLongitude(longitudeUser); 
    query.addSnapshotListener(new EventListener<QuerySnapshot>() {
        @Override
        public void onEvent(@Nullable QuerySnapshot documentSnapshots, @Nullable FirebaseFirestoreException e) {
            for (DocumentChange doc : documentSnapshots.getDocumentChanges()){
                if (doc.getType() == DocumentChange.Type.ADDED){

                    AnuncioPrincipal anuncioPrincipal1 = doc.getDocument().toObject(AnuncioPrincipal.class);
                    Location localAnuncioAtual = new Location("ProviderAun");

                    localAnuncioAtual.setLatitude(anuncioPrincipal1.getLatAnun());
                    localAnuncioAtual.setLongitude(anuncioPrincipal1.getLongAnun());
                    Log.i("valor2848", "onEvent: "+localizacaoUser.distanceTo(localAnuncioAtual)/1000+" Km Used by" +
                            anuncioPrincipal1.getCidadeAnunciante()); // CityUser - Actual City

                }
            }
        }
    });

基本上我想添加一个额外的字段,用于对 Recycler 中列出的数据进行排序,但这不在 Firestore 中,因为如果它在 Firestore 中,每个用户每分钟都会更改此变量。

【问题讨论】:

  • 乍一看,如果您需要不同的排序顺序,执行不同的查询对我来说似乎是明智的。你是在说:“但这让我付出了高昂的代价,而且不是很有效”你能解释一下你的意思吗?
  • 我们按咨询付费,所以如果我按州进行咨询...所以这会导致很多录音,因为每个用户与每个对象都有一段距离...想象一下有一千个用户的情况对于 10 个对象 .. .
  • 您可能想要验证该假设。如果您的文档没有更改,它们将从本地缓存中读取,并且您不会为每次读取付费。如果文档确实发生了变化,您实际上应该从数据库服务器重新读取它们以确保您拥有最新的数据。在后一种情况下,您可能需要考虑改用 Firebase 的实时数据库,这在您有许多小型写入操作时更具成本效益。
  • 我正在尝试实现您在下面回答的内容,今天,我使用的是 Firebase Recycler Firestore,对于此类数据,您不会将列表传递给 Recycler,但是,是的, Options 对象,例如:options = new FirestoreRecyclerOptions.Builder &lt;AnuncioPrincipal&gt; () .setQuery (query, AnuncioPrincipal.class) .build (); adapter.updateOptions (options); 即使使用Options 来更新,它还有如何改变的吗?

标签: android firebase google-cloud-firestore


【解决方案1】:

您可以向 AnuncioPrincipal 添加一个不会从 Firestore 读取(或写入)的字段:

public class AnuncioPrincipal {
    ...

    @Exclude
    public double distance

    ...
}

您可以在从DocumentSnapshot 读取对象后设置此(仅限客户端)字段:

AnuncioPrincipal anuncioPrincipal1 = doc.getDocument().toObject(AnuncioPrincipal.class);
anuncioPrincipal1.distance = ...

然后您可以使用这个新的distance 属性对您在视图中显示的列表中的项目进行排序,例如:Sort ArrayList of custom Objects by property

【讨论】:

  • 我需要更新从 Firestore 中排除的字段(距离)
  • 每次更改值时都必须重新排序列表中的项目。然后您的适配器/视图将根据新值进行更新。
  • 这是个问题,当我们使用 Firestore Recycler Adapter 时,列表不可用且无法访问,没有列表“存在”...
  • 是否可以通过 Firestore 中的 @Exclude 字段进行排序?
  • 是的,因为排序发生在服务器上,而Exclude 发生在客户端,它们不应该干涉。
【解决方案2】:

思考了几个小时后,我决定使用这个逻辑:

query.addSnapshotListener(new EventListener<QuerySnapshot>() {
@Override
public void onEvent(@Nullable QuerySnapshot documentSnapshots, @Nullable FirebaseFirestoreException e) {
for (DocumentChange doc : documentSnapshots.getDocumentChanges()){
if (doc.getType() == DocumentChange.Type.ADDED){
AnuncioPrincipal anuncioPrincipal1 = doc.getDocument().toObject(AnuncioPrincipal.class);
Location localAnuncioAtual = new Location("ProviderAun");

                                                    localAnuncioAtual.setLatitude(anuncioPrincipal1.getLatAnun());
                                                    localAnuncioAtual.setLongitude(anuncioPrincipal1.getLongAnun());
             anuncioPrincipal1.getCidadeAnunciante());
double distancia1 = Math.round(localizacaoUser.distanceTo(localAnuncioAtual)/1000);   // Distance in Km                                                 adapter.getItem(doc.getNewIndex()).setDistancia(distancia1); // SetDistance Between to Adapter
                                                    adapter.notifyDataSetChanged();
                                                }
                                            }
                                        }
                                    });

并使用本地数据(不托管在 Firestore 数据库上)更新 RecyclerView,为此我使用离线数据(缓存)创建了新适配器,并在我的 recyclerView.setAdapter(adapter2) 上使用此适配器,这很好。

【讨论】: