如何使用事务更新子节点下的多个子节点? [英] How to update multiple children under child node using a transaction?

查看:79
本文介绍了如何使用事务更新子节点下的多个子节点?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是我的数据结构,如何组织(firebase数据库):

Here's my data structure, how it is organized (firebase database):

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

我正在构建一个包含产品列表的购物应用程序.客户可以选择要购买的商品并下订单.当他们这样做时,产品的数量将根据他们选择的数量而增加. 假设某客户选择购买2单位的item2和5单位的item4,当一个客户发送请求时,它将在另一个位置写入以下数据:

I'm building a shopping app that has a list of products. Customers can choose what they want to buy and make an order. When they do the product's quantities would increase based on what they've chosen. Say a customer chose to buy 2 units of item2 e 5 units of item4, when one sends a request it will write at a different location with the following data like so:

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

然后,列表将更新为(基于onCreate方法):

Then, the list would update to (based on onCreate method):

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

但是,让我们假设另一个客户同时提出了一个请求,产品列表必须承认这一点.

But, let's suppose another customer did a request at the same time, the product list must acknowledge that.

我很了解firebase交易,因此必须执行 作为交易而不是更新. 但是,在此处进行彻底搜索的所有示例仅显示了如何更新单个节点而不是多个子节点.

I'm well aware of the firebase transactions, and this must be implemented as a transaction rather than an update. However, all the examples that a thoroughly searched here only show how to update a single node and not multiple children.

我正在使用云函数来完成此操作,这意味着我正在使用打字稿.

I'm using cloud functions to accomplish that, that means I'm using typescript.

使用事务更新多个子级的最佳方法是什么?

What would be the best approach to update multiple children using a transaction?

怎么可能只获得并增加所需的节点?

How would be possible to only get and increment only the desirable nodes?

拜托,任何帮助将不胜感激.

Please, any help would be much appreciated.

编辑:Frank van Puffelen回答了我的问题后,我决定更清楚地说明我需要做的事情.

EDIT: After Frank van Puffelen answer my question I decided to make it more clear to explain exactly what I need to do.

我只希望更新名为 productsList 一个节点,在此示例中,其子节点 item2 child4 .

I wish only to update one node named productsList and, in this example, its child nodes item2 and child4.

这里有一些代码可以更好地说明它:

Here's some code to illustrate it better:

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
}

推荐答案

事务在JSON树中的单个节点上运行,但可以在树中的任何节点上运行.

Transactions run on a single node in your JSON tree, but they can run on any node in that tree.

这意味着,如果需要以事务方式更新多个节点,则需要在这些节点的共同祖先处运行事务.因此,如果您需要同时更新ordersproductsList下的数据,则需要在它们的共同祖先运行事务.

This means that if you need to transactionally update multiple nodes, you will need to run a transaction at a common ancestor of those nodes. So if you need to update data under both orders and productsList, you'd need to run a transaction at the common ancestor of those.

请记住:

  • 事务首先读取该位置的值,然后将其返回给客户.这意味着您的事务在树中运行的越高,您将使用的带宽就越多.
  • 如果另一个客户端在读取和写入之间更改了数据,则将自动重试事务.在更高级别的位置上执行此操作,使交易更有可能被争用,即多个客户端同时在该位置下更新数据.

一种选择是使用多位置更新.与事务不同,多位置更新不会读取整个公共祖先的值,并且不会自动重试.

One alternative is to use a multi-location update. Unlike a transaction, a multi-location update doesn't read the value of the entire common ancestor, and doesn't auto-retry.

此方法要考虑的一些缺点/事情:

Some disadvantages/things to consider in this approach:

  • 如果新值取决于现有值,则仍然必须自己读取这些值.但是,与事务相比,优点是您可以读取要更新的精确值,而不用读取整个共同祖先.
  • 多位置更新只是更新,这意味着它们没有检测冲突更新的机制.您可以在安全规则中实施此操作,但绝对不容易.
  • 多位置更新不会自动重试,因此,如果安全规则拒绝更新(例如:如果另一个客户端刚刚更新了相同的值),则您必须自己在客户端代码中进行处理

有关此方法的更多信息,请在此处查看我的答案:

For some more on this approach, see my answer here: Is the way the Firebase database quickstart handles counts secure?

我能想到的最后一种选择是在可控制并行性的受信任环境中运行此代码.例如,假设您在常规节点进程中运行它,那么您可以确保仅运行该进程的单个实例.然后,如果您还确保只有该(管理)过程可以更新这些值,则不需要事务处理就可以进行更新,并且可以更好地进行扩展.

The final alternative I can think of is to run this code in a trusted environment where you control parallelism. Say for example you run it in a regular node process, then you can ensure there is only a single instance of the process running. And if you then also ensure that only this (administrative) process can update those values, you don't need a transaction for the update, and things will scale much better.

这篇关于如何使用事务更新子节点下的多个子节点?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆