Правильный способ обновления нескольких документов внутри транзакции - PullRequest
7 голосов
/ 24 мая 2019

TL; DR Должен ли я использовать Transaction.getAll() или использовать цикл for и обновлять документы по одному, используя Transaction.get()

рассмотрим следующую схему:

- someTopLevelCollection
   - accountId1
       - projects
       - tasks
       - users
  - accountId2
       - projects
       - tasks
       - users

Всякий раз, когда проект / задача создается в проектах, соответственно подгруппе задач, счетчики в коллекции пользователей обновляются, скажем, projectsCount и tasksCount.

Ссылки на пользователей хранятся внутри проекта и задач в виде массива userIds следующим образом:

Примечание: другие поля удалены для краткости

структура проекта / задачи:

{
   "name": "someName",
   "status": "someStatus",
   "users": [
       "userId1",
       "userId2",
       ....
   ],
   ...
}

Теперь мне нужно обновить, скажем, счетчик для всех пользовательских идентификаторов в массиве пользователей, используя транзакцию.

Метод 1:

const accountId = context.params.accountId;
const userIds = snapshot.data().users;

userIds.forEach(userId => {

    const userDocRef = db.collection(someTopLevelCollection)
        .doc(accountId)
        .collection('users')
        .doc(userId);

    let transaction = db.runTransaction(transaction => {
        return transaction.get(userDocRef)
            .then(doc => {
                const snapshotData = doc.data();
                let newCounterValue = snapshotData[counterName] + 1;
                transaction.update(userDocRef, {counterName: newCounterValue});
                return Promise.resolve(`Incremented ${counterName} to ${newCounterValue}`);
            });

    }).then(result => {
        console.log('Transaction success!', result);
        return true;

    }).catch(err => {
        console.error('Transaction failure:', err);
        return false;
    });

});

Метод 2:

const accountId = context.params.accountId;
const userIds = snapshot.data().users;

let userDocRefs = [];
userIds.forEach(userId => {
    const userDocRef = db.collection(someTopLevelCollection)
        .doc(accountId)
        .collection('users')
        .doc(userId);
    userDocRefs.push(userDocRef)
});

let transaction = db.runTransaction(transaction => {
    return transaction.getAll(userDocRefs)
        .then(docs => {

            docs.forEach(doc => {
                const snapshotData = doc.data();
                let newCounterValue = snapshotData[counterName] + 1;
                transaction.update(doc.ref, {counterName: newCounterValue});
            });
            return Promise.resolve('Completed transaction successfully');

        });

}).then(result => {
    console.log('Transaction success!', result);
    return true;

}).catch(err => {
    console.error('Transaction failure:', err);
    return false;

});

Ниже приведены мои вопросы:

  1. когда внешнее изменение документа происходит, когда getAll() находится под выполнение, - все документы, выбранные снова для поддержки Консистенция . Если да, то какой вариант использования getAll ()?
  2. Когда транзакция запускается одна за другой с использованием цикла for и изменение документа происходит внешне по отношению к текущему документу изменено в транзакции, - транзакция повторена только для этого документ

Спасибо.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...