Как обновить несколько дочерних узлов под дочерним узлом с помощью транзакции? - PullRequest
0 голосов
/ 10 марта 2019

Вот моя структура данных, как она организована (база данных Firebase):

 -database
  -productsList
    -item1: 0
    -item2: 0
    -item3: 0
    -item4: 0
  -orders
    -order1:
      -...
    -order2:
      -...
    -...

Я создаю приложение для покупок со списком продуктов.Клиенты могут выбрать, что они хотят купить и сделать заказ.Когда они это сделают, количество продукта увеличится в зависимости от того, что они выбрали.Скажем, клиент решил купить 2 единицы товара 2 и 5 единиц товара 4, когда кто-то отправляет запрос, он напишет в другом месте со следующими данными:

-orders
 -orderKey
  -items
   -item2: 2
   -item4: 5

Затем список обновится.to (на основе метода onCreate):

-productsList
 -item1: 0
 -item2: 2
 -item3: 0
 -item4: 5

Но давайте предположим, что другой клиент одновременно сделал запрос, список продуктов должен это подтвердить.

Мне хорошо известны транзакции Firebase, и это должно быть реализовано как транзакция, а не как обновление.Тем не менее, все примеры, которые тщательно изучены здесь, показывают, как обновить один узел, а не несколько дочерних узлов.

Для этого я использую облачные функции, это означает, что я использую машинопись.

Каков наилучший подход для обновления нескольких дочерних объектов с помощью транзакции?

Как можно получить и увеличить только желаемые узлы?

Пожалуйста, любая помощь будет принята с благодарностью.


РЕДАКТИРОВАТЬ : После того, как Фрэнк ван Пуффелен ответил на мой вопрос, я решил прояснить, что именно нужно делать.

Я хочу обновить один узел с именем productsList и, в этом примере, его дочерние узлы item2 и child4 .

Вот некоторый код, чтобы проиллюстрировать это лучше:

import * as functions from 'firebase-functions';
import * as admin from 'firebase-admin';
admin.initializeApp(functions.config().firebase)

export const onOrderCreate = functions.database
.ref('/orders/{oid}')
.onCreate(async (snapshot, context) => {
    const orderId = context.params.oid
    console.log(`new order made: ${oid}`)

    const orderData = snapshot.val()
    const items = getProductsAndQuantities(orderData)
    const path = 'productsList'

    return admin.database().ref(path).transaction(items => {
        // I would like to know if there's a way to update only the bought items, like
        const updatedList = {
            'item2': item2oldValue + 2,
            'item4': item2oldValue + 5 
        }
        return updatedList
    })

})

// Get the order data and return only the items and its quantities
function getProductsAndQuantities(data: any): Object {
    // Return items, exemple
    const products = {
        'item2': 2,
        'item4': 5 
    }

    return products
}

1 Ответ

0 голосов
/ 10 марта 2019

Транзакции выполняются на одном узле в вашем дереве JSON, но они могут выполняться на любом узле в этом дереве.

Это означает, что если вам необходимо транзакционно обновить несколько узлов, вам нужно будет выполнить транзакцию с общим предком этих узлов. Поэтому, если вам нужно обновить данные как с orders, так и с productsList, вам необходимо выполнить транзакцию с общим предком из них.

Просто имейте в виду, что:

  • Транзакция сначала читает значение в местоположении и возвращает его вашему клиенту. Это означает, что чем выше в дереве ваша транзакция, тем больше пропускной способности вы будете использовать.
  • Транзакции автоматически повторяются, если другой клиент изменил данные между чтением и записью. Выполнение этого в расположении более высокого уровня повышает вероятность того, что транзакция будет подтверждена, т.е. несколько клиентов одновременно обновляют данные в этом расположении.

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

Некоторые недостатки / особенности, которые следует учитывать при таком подходе:

  • Если новые значения зависят от существующего значения, вам все равно придется прочитать значения самостоятельно. Но преимущество над транзакцией заключается в том, что вы можете прочитать точные значения, которые хотите обновить, вместо того, чтобы читать всего общего предка.
  • Обновления с несколькими местоположениями - это просто обновления, что означает, что у них нет механизма обнаружения конфликтующих обновлений. Это то, что вы можете реализовать в правилах безопасности, но это определенно далеко не тривиально.
  • Обновления для нескольких местоположений не повторяются автоматически, поэтому, если правила безопасности отклоняют обновление (например: если другой клиент только что обновил те же значения), вам придется обрабатывать это в коде на стороне клиента самостоятельно .

Подробнее об этом подходе см. Мой ответ здесь: Безопасен ли способ быстрого запуска базы данных Firebase?


Последняя альтернатива, которую я могу придумать, - запустить этот код в надежной среде, где вы управляете параллелизмом. Скажем, например, что вы запускаете его в обычном процессе узла, тогда вы можете убедиться, что запущен только один экземпляр процесса. И если затем вы также убедитесь, что только этот (административный) процесс может обновлять эти значения, вам не потребуется транзакция для обновления, и все будет масштабироваться намного лучше.

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