是否可以在DynamoDB中嵌套嵌套字段?

时间:2016-03-01 19:04:18

标签: amazon-dynamodb upsert

我想' upsert' DynamoDB中的文档。也就是说,我想指定一个键和一组字段/值对。如果没有包含该密钥的文档,我想要使用该密钥创建的文档以及我指定的键/值对。如果存在具有该键的文档,我希望将我指定的字段设置为指定的值(如果之前不存在这些字段,则应添加它们)。现有文档中任何其他未指定的字段都应该保持不变。

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

但是,如果没有"foo.bar": 42对象,我似乎无法设置foo(就像根本没有指定字段的文档的情况一样,而且我的'upsert'表现为'插入'。

几年前我在AWS论坛上发现了a discussion这似乎意味着我想要做的事情无法完成,但我希望最近有所改变,或者有人知道一种方法吗?

3 个答案:

答案 0 :(得分:1)

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

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

希望这会有所帮助:)

答案 1 :(得分:0)

  

UpdateItem表现得像一个" upsert"操作:如果表中存在该项,则更新该项,但如果不存在,则添加(插入)新项。   http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/SQLtoNoSQL.UpdateData.html

答案 2 :(得分:0)

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

它需要两个UpdateItem调用(可能取决于嵌套级别吗?)。我只需要一个级别,所以我做到了:

  1. 使用attribute_exists条件更新项目,以将顶级属性创建为空白地图(如果尚不存在)。如果整个项目丢失或存在并且具有您不想丢失的其他先前存在的属性,则此方法将起作用。

  2. 然后执行第二级更新项目以更新嵌套值。只要父母存在(例如:在我的情况下为空的地图),它就很好用。

给人的印象是您没有使用python,但这是在以下项中完成嵌套属性的upsert的python代码:

{
  "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}',
    )