【问题标题】:Is it possible to upsert nested fields in DynamoDB?是否可以在 DynamoDB 中插入嵌套字段?
【发布时间】:2016-06-14 08:44:45
【问题描述】:

我想在 DynamoDB 中“更新”一个文档。也就是说,我想指定一个键和一组字段/值对。如果不存在具有该键的文档,我希望使用该键和我指定的键/值对创建一个文档。如果存在带有该键的文档,我希望将我指定的字段设置为指定的值(如果这些字段之前不存在,那么应该添加它们)。现有文档中的任何其他未指定字段都应保留。

当我设置的字段/值对都是顶级字段时,我似乎可以通过 UpdateItem 调用很好地做到这一点。如果我有嵌套结构,UpdateItem 将用于设置嵌套字段,只要结构存在。也就是说,如果我现有的文档有"foo": {},那么我可以成功设置"foo.bar": 42

但是,如果已经没有 foo 对象,我似乎无法设置 "foo.bar": 42(就像在根本没有具有指定字段的文档的情况下,我的“upsert”是表现得像一个“插入”。

几年前我在 AWS 论坛上找到了a discussion,这似乎暗示我想做的事情无法完成,但我希望这最近有所改变,或者也许有人知道一种方法吗?

【问题讨论】:

  • 为了给你另一个数据点,我在 2015 年 5 月(ish)调查了这个,你提到的同样的问题仍然存在。我无法实现嵌套字段 upsert 的目标,因此我不得不改变解决问题的方法以及存储数据的方式。
  • @mkobit 感谢您的数据点;这也是我得出的结论。由于我的数据具有固定数量的嵌套级别,因此我最终将其存储为扁平化,并使用名为 foo_bar 的字段,并将编组/解编组代码添加到我的 DAO 层以对其进行翻译。这是一种痛苦,但它似乎运作良好(至少到目前为止)
  • 一年后同样的问题。烦人的部分是 Dynamo 不会抛出错误,它只是不会保存数据树的那部分。
  • 有人有解决办法吗?请在此处发布。

标签: amazon-dynamodb upsert


【解决方案1】:

UpdateItem 的行为类似于“upsert”操作:如果该项目存在于表中,则更新该项目,但如果不存在,则添加(插入)一个新项目。 http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/SQLtoNoSQL.UpdateData.html

【讨论】:

【解决方案2】:

("foo.bar": 42) 可以使用以下查询来实现:

 table.update_item(Key = {'Id' : id},
              UpdateExpression = 'SET foo = :value1',
              ExpressionAttributeValues = {':value1': {'bar' : 42}}
              )

希望这会有所帮助:)

【讨论】:

  • 但是如果foo 的初始值除了你要更新的bar 值之外还有其他键,它们不会丢失吗?例如,如果初始值为{foo: {biz: 33, bar: 0}},而您只想更改foo.bar,而保持foo 对象的其余部分不变,这可行吗?
  • 我已经回答了一个类似的问题。 stackoverflow.com/questions/35569733/… 如果可行,请检查并评论。
【解决方案3】:

我发现这个 UpdateItem 限制(顶级与嵌套属性)也令人沮丧。最终我遇到了这个答案并且能够解决这个问题:https://stackoverflow.com/a/43136029/431296

它需要两次 UpdateItem 调用(可能更多取决于嵌套级别?)。我只需要一个级别,所以我就是这样做的:

  1. 使用attribute_exists 条件更新项目以将顶级属性创建为空映射(如果它尚不存在)。如果整个项目丢失或如果它存在并且具有您不想丢失的其他预先存在的属性,这将起作用。

  2. 然后做第二级更新项来更新嵌套值。只要父级存在(例如:在我的例子中是一个空地图),它就可以很好地工作。

我的印象是你没有使用 python,但这里是 python 代码来完成在这样的项目中的嵌套属性的 upsert:

{
  "partition_key": "key",
  "top_level_attribute": {
    "nested_attribute": "value"
  }
}

python boto3 代码:

def upsert_nested_item(self, partition_key, top_level_attribute_name, nested_attribute_name, nested_item_value):
    try:
        self.table.update_item(
            Key={'partition_key': partition_key},
            ExpressionAttributeNames={f'#{top_level_attribute_name}': top_level_attribute_name},
            ExpressionAttributeValues={':empty': {}},
            ConditionExpression=f'attribute_not_exists(#{top_level_attribute_name})',
            UpdateExpression=f'SET #{top_level_attribute_name} = :empty',
        )
    except self.DYNAMODB.meta.client.exceptions.ConditionalCheckFailedException:
        pass
    self.table.update_item(
        Key={'partition_key': partition_key},
        ExpressionAttributeNames={
            f'#{top_level_attribute_name}': top_level_attribute_name,
            f'#{nested_attribute_name}': nested_attribute_name
        },
        ExpressionAttributeValues={f':{top_level_attribute_name}': nested_item_value},
        UpdateExpression=f'SET #{top_level_attribute_name}.#{nested_attribute_name} = :{top_level_attribute_name}',
    )

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-06-15
    • 2018-11-18
    • 1970-01-01
    • 2021-08-14
    相关资源
    最近更新 更多