如何从一个集合中删除一个文档并在另一个集合中创建文档,所有这些都在Flutter中的Firestore的单个事务中完成

twh00eeo  于 2023-11-21  发布在  Flutter
关注(0)|答案(1)|浏览(86)

要删除分类广告在我的应用程序中,我有一个两步的过程,其中包括:
1.在集合中创建新文档,同时更新另一个文档;
1.通过更新“已删除”来更新广告:true字段。
我希望它是同一事务的一部分,是原子的。
我知道一个事务可以在get上运行多次,而这些都必须在开始时:这让我很困惑,因为我不会有新创建的文档的多个副本。
因此,我将感谢您的帮助,告诉我如何做到这一点?
我现有的代码如下:

// Deletes the ad or throw an error if it does not exist or if an error occured
  Future<void> transactionStoreDelete() async {
    final fs = FirebaseFirestore.instance;

    // == Move assets to to-be-deleted collections for future actual removal
    // from our servers and services
    // Note that if we do not succeed at moving the video assets to the
    // collection, there would be a yet-to-be-delvelopped server worker that
    // find unreferenced video and stream assets that will remove them from the
    // cloud and our services.
    try {
      await storeMarkVideoAndStreamToBeDeleted();

      await FirebaseFirestore.instance.runTransaction((t) async {
        /// Reads the ad document
        final doc = await t.get(fs.collection("ads").doc(id));

        if (doc.exists) {
          t.delete(doc.reference);
        }
      });
    } catch (e) {
      debugPrint(
          "Could not move video assets to to-be-deleted collections: $e");
    }
  }

字符串
其中storeMarkVideoAndStreamToBeDeleted如下:

/// Clean up video assets byt doing the following:
  /// 1) Move the video and video stream to the to-be-deleted related collections;
  /// 2) Nullify [videoUrl] and [stream] in the current ad instance;
  /// 3) Update the ad in the collection.
  ///
  Future<void> storeMarkVideoAndStreamToBeDeleted() async {
    if (videoUrl != null) {
      try {
        // == Create record set in to be delted video
        await FirebaseFirestore.instance.collection("toBeDeletedVideos").add({
          ...trackingInformation,
          "url": videoUrl!,
        });
      } catch (e) {
        debugPrint("Could not move the video to be deleted: $e");
      }
    }

    if (stream != null) {
      try {
        // == Create record set in  to be deleted stream
        await FirebaseFirestore.instance.collection("toBeDeletedStreams").add({
          ...trackingInformation,
          "streamId": stream!.id,
        });
      } catch (e) {
        debugPrint("Could not move the stream video to be deleted: $e");
      }
    }

    // == Now erase reference to them
    return FirebaseFirestore.instance
        .collection("ads")
        .doc(id)
        .update({
      "videoUrl": null,
      "stream": null,
    });
  }


[更新]在阅读评论后,试着澄清问题。
[更新2]写了收藏品的名称以供澄清。
[更新3]我想实现的伪代码中的工作流程:

t = openTheTransaction()

ad = 
adsCollection.getTheAdDocumentReferenceFrom(t)

t.create(toBeDeletedVideosCollection.createDocumentWith(ad))

t.create(toBeDeletedStreamsCollection.createDocumentWith(ad))

t.update(ad, {deleted:true})

t.commit()


希望对你有帮助。

zrfyljdw

zrfyljdw1#

更新您的问题的以下说明

您可以在Transaction中实现问题中的伪代码,如下所示:

id = ...;
db = FirebaseFirestore.instance;
await db.runTransaction((t) async {
        
    final adDocRef = db.collection("ads").doc(id);
    final adDocSnapshot = await t.get(adDocRef);

    final trackingInformation = ...; /// I understand that you get trackingInformation from the adDocSnapshot

    final toBeDeletedVideoDocRef = db.collection("toBeDeletedVideos").doc();
    t.set(
      toBeDeletedVideoDocRef,
      {
        ...trackingInformation,
        "url": videoUrl!,
      } 
    );

    final toBeDeletedStreamDocRef = db.collection("toBeDeletedStreams").doc();
    t.set(
      toBeDeletedStreamDocRef,
      {
        ...trackingInformation,
        "streamId": stream!.id,
      } 
    );

    t.update(adDocRef, {"deleted":true});

});

字符串
请注意,我们使用Transaction的set()方法以及(CollectionReference的)doc()方法,而不提供任何path以获取自动生成的docID。

初始答案

要删除分类广告在我的应用程序中,我有一个两步的过程,其中包括:

  • 在集合中创建新文档,同时更新另一个文档;
  • 通过更新“删除”:true字段更新广告。
    我希望它是同一事务的一部分,是原子的。

如果我正确地理解了你的问题,你希望上面的3个动作(即创建一个新文档和更新两个文档)以原子方式完成。
这与storeMarkVideoAndStreamToBeDeleted()函数中的操作无关,该函数在上述过程之前被调用。
在这种情况下,您不需要使用事务,因为您不读取操作集中的任何文档,但您需要使用批量写入,它“原子地完成并可以写入(即创建,更新和删除)多个文档”。

相关问题