Firestore:在事务中读取多个文档

时间:2018-03-16 21:57:35

标签: swift firebase google-cloud-firestore

当我运行Firestore事务时,它给出了错误:

  

“交易中读取的每个文件也必须写在该交易中。”

但我在交易中尝试阅读的所有文件也都写在下面的代码中?

    db.runTransaction({ (transaction, errorPointer) -> Any? in
    let doc1: DocumentSnapshot
    let doc2: DocumentSnapshot
    let doc3: DocumentSnapshot

    do {
        try doc1 = transaction.getDocument(self.doc1Ref)
        try doc2 = transaction.getDocument(self.doc2Ref)
        try doc3 = transaction.getDocument(self.doc3Ref)
    } catch let fetchError as NSError {
        errorPointer?.pointee = fetchError
        return nil
    }



    // WRITES TO DOC1, DOC2, DOC3
    guard let userPostCount = doc1.data()?["postCount"] as? Int,
        let locationPostCount = doc2.data()?["postCount"] as? Int,
        let itemPostCount = doc3.data()?["postCount"] as? Int,
        let locationAvgRating = doc2.data()?["averageRating"] as? Float,
        let itemAvgRating = doc3.data()?["averageRating"] as? Float else { return nil }


    // Create post on another document not in transaction
    transaction.setData(post.dictionary, forDocument: self.doc4Ref)


    // Update counts for #userPosts, #locationPosts, #itemPosts, avgLocationRating, avgItemRating
    transaction.updateData(["postCount": userPostCount + 1], forDocument: self.doc1Ref)

    let newAvgLocationRating = ((avgLocationRating * Float(locationPostCount)) + Float(post.rating)) / (Float(locationPostCount) + 1.0)
    transaction.updateData(["postCount": locationPostCount + 1, "averageRating": newAvgLocationRating], forDocument: self.doc2Ref)

    let newAvgItemRating = ((avgItemRating * Float(itemPostCount)) + Float(post.rating)) / (Float(itemPostCount) + 1.0)
    transaction.updateData(["postCount": locationPostCount + 1, "averageRating": newAvgItemRating], forDocument: self.doc3Ref)


    // Add postID to user and location
    transaction.setData(["postID": self.postRef.documentID, "locationID": post.locationID, "itemID": post.itemID, "rating": post.rating, "timestamp": post.timestamp], forDocument: self.doc1Ref.collection("posts").document(self.postRef.documentID))

    transaction.setData(["postID": self.postRef.documentID, "rating": post.rating, "timestamp": post.timestamp], forDocument: self.doc3Ref.collection("posts").document(self.postRef.documentID))


    return nil
}) { (object, error) in
    if let error = error {
        print(error)
    } else {
        print("done")
    }
}

是否无法在事务中执行多个.getDocument( documentReference )?

还有另一种方法可以解决这个问题吗?

2 个答案:

答案 0 :(得分:1)

您应该将所有if次操作放在doelse操作中catch

不要在街区之外使用它们。

这就是错误所说的"Every document read in a transaction must also be written in that transaction." 对于前你的代码

// WRITES TO DOC1, DOC2, DOC3
guard let userPostCount = doc1.data()?["postCount"] as? Int,
    let locationPostCount = doc2.data()?["postCount"] as? Int,
    let itemPostCount = doc3.data()?["postCount"] as? Int,
    let locationAvgRating = doc2.data()?["averageRating"] as? Float,
    let itemAvgRating = doc3.data()?["averageRating"] as? Float else { return nil }

正在使用do catch block

范围之外的doc1doc2进行操作

答案 1 :(得分:0)

我刚刚注意到你正在使用Apple的快速脚本。我的答案是基于标准的JavaScript,但我希望它能帮到你。我不会使用或了解有关Swift的任何信息......

至于同时从3个文档中读取数据,这样做的方法是使用javascript' s .promise.all。虽然以下代码并不是您的解决方案,但您可以了解如何执行此操作。

你基本上将每个.get推送到一个数组中,然后你.promise.all那个数组.then迭代返回的数据。

        try {
            targetRef.get().then(function(snap) {
                if (snap.exists) {
                    for (var key in snap.data()) {
                        if (snap.data().hasOwnProperty(key)) {
                            fetchPromise = itemRef.doc(key).get();
                            fetchArray.push(fetchPromise);
                        }
                    }
                    Promise.all(fetchArray).then(function(values) {
                        populateSelectFromQueryValues(values,"order-panel-one-item-select");
                        if(!selectIsEmpty("order-panel-one-item-select")){
                            enableSelect("order-panel-one-item-select");
                        }
                    });
                }
            }).catch(function(error) {
                toast("error check console");
                console.log("Error getting document:", error);
            });
        }