2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

FirestoreでonSnapshotがadd/update/set/deleteの結果より先に呼ばれる

Last updated at Posted at 2020-04-12

問題

FiresotreでCollectionの更新をListenしている場合、addの結果(id取得前)より先にonSnapshotが発火するようである。

自分自身がaddした結果かどうか判定する必要がある場合、addの結果のdoc IDが手に入っていない状態ではそれができない。

下記の例で、 Aのadd処理の後、Firebaseから処理が非同期的に帰ってきてBでDocumentのIDを取得できる。この時、自分が追加したデータのリストとしてmyDataに格納する。onSnapshotでは他人からのデータ追加も含めて通知がやってくるが、Bの前にCが発火するため、自分のデータを判定することができない。

var myData = [];

//......

firebase.firestore().collection("hoge").add({fuga: "fugu"}) // A
.then(async (docRef) => {
        myData.push(docRef.id);  // B
});

firebase.firestore().collection("hoge").onSnapshot((snapshot) => {
    snapshot.docChanges().forEach(async (change) => {
        if (change.type === "added") { // C
            if(myData.indexOf(change.doc.id)>=0){ /* 自分がaddしたデータ */ }
            else{ /* 自分以外のデータ, 処理 */ }
        }
    });
});

案0

自分自身が追加したデータも他からのデータも特に区別する必要のないような設計にする。これができれば一番良いし、原則これを目指すべきだろう。ただ諸事情によりできない場合もある。

案1

Record自体に一意性が十分保証されるような乱数等を入れおいて判定する。

var myData = [];

//......

var randv = rand(); // 本当はもっと堅牢なGUID生成
myData.push(randv);
firebase.firestore().collection("hoge").add({fuga: "fugu", token:randv}) // A
.then(async (docRef) => {
        // myData.push(docRef.id);  // B
});

firebase.firestore().collection("hoge").onSnapshot((snapshot) => {
    snapshot.docChanges().forEach(async (change) => {
        if (change.type === "added") { // C
            if(myData.indexOf(change.doc.data().token)>=0){ /* 自分がaddしたデータ */ }
            else{ /* 自分以外のデータ, 処理 */ }
        }
    });
});

案2

A -> Bの間にmyDataを参照する処理が入らなければ良い。同期の仕組みであるMonitor的なものを導入してそれを阻止する。こちらのMonitorクラスを使うと下記のようにかける。

var monitor = new Monitor();
var myData = [];

//.........

await monitor.enter();
firebase.firestore().collection("hoge").add({fuga: "fugu"}) // A
.then(async (docRef) => {
        myData.push(docRef.id);  // B
})
.finally(()=>{
        monitor.exit();
});

firebase.firestore().collection("hoge").onSnapshot((snapshot) => {
    snapshot.docChanges().forEach(async (change) => {
        if (change.type === "added") { // C
            await monitor.enter();
            if(myData.indexOf(change.doc.id)>=0){ /* 自分がaddしたデータ */ }
            else{ /* 自分以外のデータ, 処理 */ }
            monitor.exit();
        }
    });
});
2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?