Contents
本日こそ最終回
次の課題へ掛かります。
https://myapp-7bf76.web.app/#top
トランザクションを使う前
アカウント削除時に
・全体チャットデータの削除
・firestoreに出したプロフィール画像他の参照可能データの削除
これらを対応しなくてはならず。
以下のように記述していたら、案の定うまくいかなかったのです。
// アカウント削除
document.querySelector("#remove_account_form").addEventListener("submit", function(event) {
if(confirm('アカウントを削除します。本当によろしいですか?')){
document.querySelector('#remove_account_form button').setAttribute('disabled', true);
document.querySelector('#remove_account_form button').innerText = '削除中...';
var user = firebase.auth().currentUser;
var credential = firebase.auth.EmailAuthProvider.credential(
user.email,
getElementValue('remove_account_password')
);
user.reauthenticateWithCredential(credential).then(function() {
// User re-authenticated.
user.delete().then(function() {
var db = firebase.firestore();
// チャットデータを削除
var openchatsRef = db.collection("openchats");
var query = openchatsRef.where("uid", "==", user.uid);
query.get()
.then(function(querySnapshot) {
querySnapshot.forEach(function(doc) {
db.collection("openchats").doc(doc.id).delete().then(function() {
console.log("Document successfully deleted!");
}).catch(function(error) {
console.error("Error removing document: ", error);
});
// // doc.data() is never undefined for query doc snapshots
// console.log(doc.id, " => ", doc.data());
});
})
.catch(function(error) {
console.log("Error getting documents: ", error);
});
// プロフィールデータを削除
db.collection("users").doc(user.uid).delete().then(function() {
console.log("Document successfully deleted!");
}).catch(function(error) {
console.error("Error removing document: ", error);
});
alert('アカウントを削除しました。ご利用ありがとうございました。');
firebase.auth().signOut();
}).catch(function(error) {
var errorCode = error.code;
var errorMessage = error.message;
alert(errorCode + ', ' + errorMessage);
});
}).catch(function(error) {
var errorCode = error.code;
var errorMessage = error.message;
alert(errorCode + ', ' + errorMessage);
});
}
event.preventDefault();
}, false);
全体チャットから削除する対象のdocumentを検索してきてforEachで削除するまでは正しかったのですが、そちらの処理が終わる前にsignOutが走ってしまいます。
これを解決する為にはトランザクションを使います。
トランザクションを使ってみます
但し公式のサンプルはdocument idが指定されていますが、私の場合は検索してループさせないとなりませんでした。
// Create a reference to the SF doc.
var sfDocRef = db.collection("cities").doc("SF");
// Uncomment to initialize the doc.
// sfDocRef.set({ population: 0 });
return db.runTransaction(function(transaction) {
// This code may get re-run multiple times if there are conflicts.
return transaction.get(sfDocRef).then(function(sfDoc) {
if (!sfDoc.exists) {
throw "Document does not exist!";
}
// Add one person to the city population.
// Note: this could be done without a transaction
// by updating the population using FieldValue.increment()
var newPopulation = sfDoc.data().population + 1;
transaction.update(sfDocRef, { population: newPopulation });
});
}).then(function() {
console.log("Transaction successfully committed!");
}).catch(function(error) {
console.log("Transaction failed: ", error);
});完遂した実装は以下の通り。
最初に22行目にもreturnをつけるのに気がつかず、37行目の公開プロフィール情報の削除の方が先に動いてしまい元の木阿弥でした。
22行目にreturnを付け、定義したtransactionが全て完了した段階でthenに飛ばすことができました。
// アカウント削除
document.querySelector("#remove_account_form").addEventListener("submit", function(event) {
event.preventDefault();
if(confirm('アカウントを削除します。本当によろしいですか?')){
document.querySelector('#remove_account_form button').setAttribute('disabled', true);
document.querySelector('#remove_account_form button').innerText = '削除中...';
var user = firebase.auth().currentUser;
var db = firebase.firestore();
// チャットデータを削除
// var openchatsRef = db.collection("openchats");
var user = firebase.auth().currentUser;
var credential = firebase.auth.EmailAuthProvider.credential(
user.email,
getElementValue('remove_account_password')
);
const openchatsRef = db.collection('openchats'); // .where("uid", "==", user.uid)
const usersRef = db.collection('users').doc(user.uid);
return db.runTransaction(function(transaction) {
// 全体チャットデータの削除
var query = openchatsRef.where("uid", "==", user.uid);
query.get()
.then(async function(querySnapshot) {
querySnapshot.forEach(function(doc) {
return transaction.get(openchatsRef.doc(doc.id)).then(function(sfDoc) {
transaction.delete(openchatsRef.doc(doc.id));
});
});
// console.log(querySnapshot.docs);
});
// 公開プロフィール情報削除
return transaction.get(usersRef).then(function(sfDoc) {
transaction.delete(usersRef);
});
}).then(function() {
// storageのプロフィール画像削除
var storageRef = firebase.storage().refFromURL(user.photoURL);
// Delete the file
storageRef.delete().then(function() {
// File deleted successfully
console.log('File deleted successfully');
user.reauthenticateWithCredential(credential).then(function() {
user.delete().then(function() {
alert('アカウントを削除しました。ご利用ありがとうございました。');
firebase.auth().signOut();
location.reload();
});
});
}).catch(function(error) {
// Uh-oh, an error occurred!
});
}).catch(function(error) {
console.log(error.line);
console.log("Transaction failed: ", error);
});
}
event.preventDefault();
}, false);
加えて、43行目と46行目でしれっとプロフィール画像の処理を追加し、ひととおりやりたいことはやれたので、エキシビジョン的に動く状態で公開しておきます。
なおgithubはこちらに公開しています。