firebase 如何从Flutter中的两个firestore集合中原子删除

new9mtju  于 12个月前  发布在  Flutter
关注(0)|答案(2)|浏览(121)

我有两个集合:Firestore中的用户和广告。
当我删除一个用户文件的用户集合我也需要删除他的所有广告的广告集合。
批量版本是否正确?

Future<void> storeMarkAsDeleted() async {
    final fs = FirebaseFirestore.instance;
    final writeBatch = fs.batch();

    // = Open a transaction to perform both operations
    final user = await fs.collection(collectionName).doc(id));

      /// Reads the ad document
      final ads = await fs
          .collection(collectionName)
          .where("ownerId", isEqualTo: id)
          .get();

      // Mark user as deleted
      writeBatch.update(user.reference, {
        "deleted": true,
      });

      // Update all docs
      for (final doc in ads.docs) {
     
        writeBatch.update(doc.reference, {
          "clearedForSale": false,
          "deleted": true,
        });
      }
      // unless commit is called, nothing happens.
      writeBatch.commit();
    }

字符串

6ioyuze2

6ioyuze21#

(我还看到了你的另一个问题Does it makes sense to batch update within a transaction in Flutter with Firebase?,关于在事务中原子地执行删除)。
一种可能性是在云函数中使用事务**。虽然您无法在通过客户端SDK(包括Firebase Flutter插件)执行的事务中执行查询,但您可以使用服务器客户端库(C#,Go,Java,Node.js,PHP,Python,Ruby)并因此在云函数中执行查询。
文档中的本页解释了这种差异的原因。
在Cloud Function中,首先删除用户文档,然后执行一个查询,返回与用户对应的ads文档,并通过在QuerySnapshot上循环删除所有文档。最好的方法是通过传递用户uid从Flutter应用调用Callable Cloud Function
沿着Node.js Cloud Functions第二代的以下行:

const { initializeApp } = require("firebase-admin/app");
const { onCall, HttpsError } = require("firebase-functions/v2/https"); 
const { getFirestore } = require("firebase-admin/firestore");

initializeApp();

exports.deleteUserDocs = onCall(async (request) => {
  const userId = request.data.userId;

  await getFirestore().runTransaction(async (transaction) => {
    const userDocRef = getFirestore().collection("users").doc(userId);
    const queryRef = getFirestore()
      .collection("ads")
      .where("ownerId", "==", userId);
    const userAdsSnapshots = await transaction.get(queryRef);

    transaction.delete(userDocRef);
    userAdsSnapshots.forEach((userAdSnap) => {
      transaction.delete(userAdSnap.ref);
    });
    return Promise.resolve();
  });

  return {result: "success"}
});

字符串
我让你添加try/catch块并管理文档中解释的潜在错误。

i7uaboj4

i7uaboj42#

但是,您应该注意,在ads文档的查询和它们的删除之间有一段很短的时间,在这段时间内,新文档可以添加到集合中,并且在提交批处理时不会标记为已删除。

相关问题