Транзакция Firestore с проблемой запроса - PullRequest
1 голос
/ 09 июля 2020

Я пытаюсь запустить транзакцию, которая требует получения данных из запроса:

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);
          });

Для моего приложения мне нужно выполнить запрос, чтобы завершить транзакцию. Я получаю сообщение об ошибке:

Ошибка транзакции: [FirebaseError: функция Transaction.get () требует, чтобы ее первый аргумент был DocumentReference, но это был: настраиваемый объект t]

Я понимаю, что для транзакции требуется ссылка на документ. Есть ли способ обойти это?

Ответы [ 2 ]

2 голосов
/ 09 июля 2020

Ближайший эквивалент - выполнить запрос с более высоким пределом, затем в транзакции снова получить do c и снова проверить необходимое условие ввода ....

// 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
  })
}

Первый параметр транзакции get действительно является ссылкой на документ, а не запросом. Это сбивает с толку, потому что documentReference.get() и transaction.get(documentReference) и `query.get () выглядят и звучат одинаково, но транзакция - это только atomi c для одного do c, а не для набора из запроса , даже один, ограниченный 1.

0 голосов
/ 09 июля 2020

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
      }));
    });
...