在嵌套字段上应用增量值

Apply delta values on nested fields

假设我有这样的记录:

{
    id: 1,
    statistics: {
        stat1: 1,
        global: {
            stat2: 3
        },
        stat111: 99
    }
}

我想更新记录对象:

{
    statistics: {
        stat1: 8,
        global: {
            stat2: 6
        },
        stat4: 3
    }
}

它应该作为增量添加到当前记录中。因此,结果记录应如下所示:

{
    id: 1,
    statistics: {
        stat1: 9,
        global: {
            stat2: 9
        },
        stat4: 3,
        stat111: 99
    }
}

是否可以一次查询完成?

您想要通用的还是特定的? 具体很简单,这是通用案例:

const updateValExpr = r.expr(updateVal);
const updateStats = (stats, val) => val
    .keys()
    .map(key => r.branch(
        stats.hasFields(key), 
        [key, stats(key).add(val(key))], 
        [key, val(key)]
    ))
    .coerceTo('object')

r.table(...)
 .update(stats => 
      updateStats(stats.without('global'), updateValExpr.without('global'))
          .merge({ global: updateStats(stats('global'), updateValExpr('global'))
 )

这里可能有一些错误,因为它未经测试,但解决方案的关键点是 updateStats 函数,事实上你可以使用 .keys()coerceTo('object') 获得所有密钥将此数组:[['a',1],['b',2]] 转换为此对象:{ a: 1, b: 2 }

编辑: 您可以递归地执行此操作,尽管堆栈有限(因为您不能直接发送递归堆栈,它们会在实际构建查询时解析:

function updateStats(stats, val, stack = 10) { 
    return stack === 0 
        ? {} 
        : val
           .keys()
           .map(key => r.branch(
                stats.hasFields(key).not(), 
                [key, val(key)],
                stats(key).typeOf().eq('OBJECT'),
                [key, updateStats(stats(key), val(key), stack - 1)], 
                [key, stats(key).add(val(key))]
            )).coerceTo('object')
}

r.table(...).update(row => updateStats(row, r(updateVal)).run(conn)

// test in admin panel
updateStats(r({
    id: 1,
    statistics: {
        stat1: 1,
        global: {
            stat2: 3
        },
        stat111: 99
    }
}), r({
    statistics: {
        stat1: 8,
        global: {
            stat2: 6
        },
        stat4: 3
    }
}))