在查询文档时,Firestore不会通知已删除的更改类型 [英] Firestore does not notify REMOVED change type when querying documents

查看:32
本文介绍了在查询文档时,Firestore不会通知已删除的更改类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我只查询Firestore集合上的新文档

  FirebaseFirestore firestore = FirebaseFirestore.getInstance();CollectionReference collectionReference = firestore.collection("my_data");EventListener< QuerySnapshot>eventListener =(快照,e)->{if(e!= null ||快照== null){返回;}对于(DocumentChange dc:snapshots.getDocumentChanges()){如果(dc == null){继续;}开关(dc.getType()){案例添加:onDocumentAdded(dc.getDocument());休息;案例修改:onDocumentModified(dc.getDocument());休息;案例删除:onDocumentRemoved(dc.getDocument());休息;}}//最后一个事件的调用时间SharedPreferences prefs = App.getInstance().getSharedPreferences("firestore",Context.MODE_PRIVATE);SharedPreferences.Editor编辑器= prefs.edit();editor.putLong("last_event_call_time",新的Date().getTime());editor.apply();}; 

我有一个方法负责注册侦听器:

 /***注册事件监听器以查询新文档,仅从上次事件调用时间进行更新和删除*/public void registerListener(ThreadTaskExecutor executor){如果(listenerRegistration!= null){返回;}SharedPreferences prefs = MyApplication.getInstance().getSharedPreferences("firestore",Context.MODE_PRIVATE);日期时间=新的日期(prefs.getLong("last_event_call_time",新的Date().getTime()));listenerRegistration = collectionReference.orderBy(时间戳").startAt(新时间戳(时间)).addSnapshotListener(executor,eventListener);}/***删除事件监听器*/公共无效removeListener(){如果(listenerRegistration == null){返回;}listenerRegistration.remove();listenerRegistration = null;} 

我还有创建,更新和删除文档的方法:

  public void add(String documentId,Map< String,Object>数据)引发异常{data.put("timestamp",FieldValue.serverTimestamp());Tasks.await(collectionReference.document(documentId).set(data));}公共无效更新(String documentId,Map< String,Object>数据)抛出异常{data.put("timestamp",FieldValue.serverTimestamp());Tasks.await(collectionReference.document(documentId).update(data));}公共无效delete(String documentId)引发异常{delete(collectionReference.document(documentId));}公共无效delete(DocumentReference docRef)引发异常{Tasks.await(docRef.delete());} 

我的执行者(在此示例中使用):

 公共静态类ThreadTaskExecutor实现了Executor {@Override公共同步void execute(Runnable命令){new Thread(command).start();}} 

好吧,我有一个应用程序(使用此代码)安装在两个设备(设备A和设备B)上.

我在两个设备中都打开了该应用程序,并且事件监听器已注册.

当我在设备A上创建内容时,设备B会收到通知(好).当我在设备A上更新某些内容时,设备B也会收到通知(很棒).当我删除设备A上的某物时,设备B也会收到通知(令人讨厌).

但是...

如果我停止了设备B上的应用程序进程(它强制删除了监听器):

如果我在设备A上创建了某些内容,请在设备B上打开应用(已注册侦听器),则会发送ADDED事件.

如果我在设备A上进行了某些更新,请在设备B上打开应用(已注册监听器),也会发送ADDED事件(很奇怪,但是我可以解决这个问题).

这是问题所在:

如果我删除了设备A上的某些内容,请在设备B上打开该应用程序(注册了侦听器),但完全没有传递REMOVED事件,因此我无法在设备B上应用此更改. >

有什么主意吗?

解决方案

这些事件的逻辑是,它们表示已更改此侦听器的先前状态.

ADDED CHANGED :添加侦听器时,每个文档都是新文档,因此会触发每个文档的 ADDED 事件

REMOVED :删除文档后添加侦听器时,数据库中不存在该文档的知识,因此不再有引发此类事件的信息.

重要的是要认识到Firestore同步状态,而不是状态更改.例如,这就是为什么您没有得到这些文档的 REMOVED 的原因,但这也意味着您可能会错过状态抵消而彼此抵消的原因.

如果要同步状态更改,则应将这些更改存储在数据库中.例如,为确保您的客户知道已删除的文档,请在文档中写入 DELETED 状态,而不是实际将其删除.

I'm querying only new documents on Firestore collection:

FirebaseFirestore firestore = FirebaseFirestore.getInstance();
CollectionReference collectionReference = firestore.collection("my_data");


EventListener<QuerySnapshot> eventListener = (snapshots, e) -> {

        if (e != null || snapshots == null) {
            return;
        }

        for (DocumentChange dc : snapshots.getDocumentChanges()) {

            if (dc == null) {
                continue;
            }


           

            switch (dc.getType()) {

                case ADDED:

                    onDocumentAdded(dc.getDocument());

                    break;

                case MODIFIED:

                    onDocumentModified(dc.getDocument());

                    break;

                case REMOVED:

                    onDocumentRemoved(dc.getDocument());

                    break;
            }
        }


        // Last event call time 
        SharedPreferences prefs = App.getInstance().getSharedPreferences("firestore", Context.MODE_PRIVATE);
        SharedPreferences.Editor editor = prefs.edit();
        editor.putLong("last_event_call_time", new Date().getTime());
        editor.apply();
    };

And I have a method responsible for registering the listener:

 /**
 * Register the event listener to query new documents, updates and removes only from the last event call time
 */
public void registerListener(ThreadTaskExecutor executor) {

    if (listenerRegistration != null) {
        return;
    }


    SharedPreferences prefs = MyApplication.getInstance().getSharedPreferences("firestore", Context.MODE_PRIVATE);
    Date time = new Date(prefs.getLong("last_event_call_time", new Date().getTime()));

    listenerRegistration = collectionReference
            .orderBy("timestamp")
            .startAt(new Timestamp(time))
            .addSnapshotListener(executor, eventListener);
}

/**
 * Removes the event listener
 */
public void removeListener() {
    if (listenerRegistration == null) {
        return;
    }
    listenerRegistration.remove();
    listenerRegistration = null;
}

I have also methods for creating, updating and deleting documents:

public void add(String documentId, Map<String, Object> data) throws Exception {

      
        data.put("timestamp", FieldValue.serverTimestamp());
      
        Tasks.await(collectionReference.document(documentId).set(data));
    }

    public void update(String documentId, Map<String, Object> data) throws Exception {

        data.put("timestamp", FieldValue.serverTimestamp());

        Tasks.await(collectionReference.document(documentId).update(data));
    }

    public void delete(String documentId) throws Exception {
        delete(collectionReference.document(documentId));
    }

    public void delete(DocumentReference docRef) throws Exception {
        Tasks.await(docRef.delete());
    }

My executor (used in this example):

public static class ThreadTaskExecutor implements Executor {

        @Override
        public synchronized void execute(Runnable command) {
            new Thread(command).start();
        }
    }

Well, I have an app (using this code) installed on two devices, device A and device B.

I open the app in both devices and the event listener is registered.

When I create something on device A, device B is notified (good). When I update something on device A, device B is also notified (great). When I remove something on device A, device B is notified as well (awsome).

However ...

If I stop the app process on device B (and it forces the listener to be removed):

If I create something on device A, open the app on device B (listener registered), ADDED event is delivered.

If I update something on device A, open the app on device B (listener registered), ADDED event is delivered as well (weird, but I could work around it).

Here is the problem:

If I delete something on device A, open the app on device B (listener registered), REMOVED event is not delivered at all, so I could not apply this change on device B.

Any idea ?

解决方案

The logic for these events is that they signal the changes to the previous state of this listener.

ADDED vs CHANGED: When you add the listener, every document is new to it, so it fires ADDED events for each of them.

REMOVED: when you add the listener after deleting a document, there is no knowledge of that document left in the database, so there's no information to fire such an event anymore.

It's important to realize that Firestore synchronizes state, not state changes. Which is for example why you don't get REMOVED for those documents, but it also means you may miss state changes that cancel each other out.

If you want to synchronize state changes, you should store those changes in the database. For example, to ensure that your clients know of the document that was deleted, write a DELETED status into the document rather than actually deleting it.

这篇关于在查询文档时,Firestore不会通知已删除的更改类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆