具有查询问题的 Firestore 事务

Firestore transaction with query issue

我正在尝试 运行 需要从查询中获取数据的事务:

firestore
          .runTransaction((transaction) => {
            const query = firestore
              .collection("Lottories")
              .doc("R3DYubrqFbbVfQNjYXfh")
              .collection("sets")
              .where("isAvailable", "==", false)
              .limit(1);
            return transaction.get(query).then((snapshot) => {
              const ticketDoc = snapshot.docs[0];
              const ticketDocData = ticketDoc.data();
              const lottoUpdate = firestore
                .collection("Lottories")
                .doc("R3DYubrqFbbVfQNjYXfh")
                .collection("sets")
                .doc(ticketDoc.id);
              const ticketUpdate = firestore
                .collection("UserLotto")
                .doc(userId)
                .collection("tickets")
                .doc("abc");
              const countUpdate = firestore
                .collection("UserData")
                .doc(userId);
              transaction.update(lottoUpdate, { isAvailable: true });
              transaction.update(countUpdate, {
                ticketCount: ticketCount - 2,
              });
              transaction.set(ticketUpdate, {
                ticketId: ticketDoc.id,
                lottoId: "abc",
                claimed: false,
              });

              return ticketDocData;
            });
          })
          .then((ticketDocData) => {
            console.log(
              "Transaction successfully committed!",
              ticketDocData
            );
            setPopScreen("ticketPurchased");
          })
          .catch((error) => {
            console.log("Transaction failed:", error);
          });

对于我的申请,我需要 运行 查询才能完成我的交易。我收到错误:

Transaction failed: [FirebaseError: Function Transaction.get() requires its first argument to be a DocumentReference, but it was: a custom t object]

我了解交易需要文件参考。有解决办法吗?

transaction.get(query) query 必须是 DocumentReference。所以你需要这样的东西:

db.collection("Lottories/R3DYubrqFbbVfQNjYXfh/sets")
    .where("isAvailable", "==", false)
    .limit(1)
    .get()
    .then((docs) => {
      db.runTransaction((transaction) => transaction.get(docs[0]).then((doc) => {
        if (doc.exists) //do something
      }));
    });

最接近的是用更高的限制做查询,然后在事务中,再次获取文档并再次检查所需的输入条件....

// this will do the OP sets/updates, but *doesn't* assume the input
// doc meets the required condition (isAvailable==true)
// return a bool indicating success
function reserveDoc(lottoDoc) {
  return firestore.runTransaction(transaction => {
    return transaction.get(lottoDoc.ref).then(ticketDoc => {
      // important, check the original condition again here
      if (ticketDoc.data().isAvailable) {
        // OP code to set/update goes here
        return true
      } else {
        return false
      }
    })
  })
}

// try a transaction on the first doc in the array.  return if successful
// otherwise, try recursively on the remainder of the array
// return a bool indicating success
function reserveOneOf(lottoDocs) {
  if (lottoDocs.length === 0) return false
  return reserveDoc(lottoDocs[0]).then(success => {
    // did it work?  if not, try another doc
    return success ? success : reserveOneOf(lottoDocs.slice(1))
  })
}


function originalOPFunction() {
  const query = firestore
    .collection("Lottories")
    .doc("R3DYubrqFbbVfQNjYXfh")
    .collection("sets")
    .where("isAvailable", "==", true)  // note, I assume the OP query had a typo, checking for false
    .limit(10);
  return query.get().then(snapshot => {
    return reserveOneOf(snapshot.docs)
  }).then(success => {
    // if !success here, the app must deal with NO docs currently meeting the criterion
    // the OP needed to handle this circumstance anyway (if the limit(1) query returned no docs
  })
}

Transaction get 的第一个参数确实是文档引用,而不是查询。这是令人困惑的,因为 documentReference.get()transaction.get(documentReference) 和 `query.get(),看起来和听起来都一样,但是事务只在单个文档上是原子的,而不是在查询的集合上, 甚至一个限制为 1.