Amazon dynamodb 当映射不存在时,如何设置DynamoDB映射属性值';还不存在

Amazon dynamodb 当映射不存在时,如何设置DynamoDB映射属性值';还不存在,amazon-dynamodb,Amazon Dynamodb,如何将属性“向上插入”到DynamoDB行。例如,SET address.state=“MA”对于某些项目,当address还不存在时 我觉得我遇到了鸡和蛋的问题,因为DynamoDB不允许您预先定义一个草率的模式 如果地址已经存在于该项目上,类型为M(用于地图),互联网告诉我可以发布更新表达式,如: SET#address.#state=:value 分别将#地址、#状态和:值适当映射到地址、状态和MA 但是如果address属性不已存在,则会出现错误: ''' ValidationExcep

如何将属性“向上插入”到DynamoDB行。例如,
SET address.state=“MA”
对于某些项目,当
address
还不存在时

我觉得我遇到了鸡和蛋的问题,因为DynamoDB不允许您预先定义一个草率的模式

如果
地址
已经存在于该项目上,类型为
M
(用于地图),互联网告诉我可以发布更新表达式,如:

SET#address.#state=:value

分别将
#地址
#状态
:值
适当映射到
地址
状态
MA

但是如果
address
属性不已存在,则会出现错误:

''' ValidationException:更新表达式中提供的文档路径对于更新无效 '''

所以。。看来我要么需要:

  • 找出一种“向上插入”
    address.state
    (例如,
    SET address={};SET address.state='MA'
    在单个命令中)
  • 发布三个(!!!)我尝试的往返,
    SET address={}失败,然后重试
  • 如果后者。。。。如何设置空白地图


    啊。。我喜欢Dynamo,但除非我遗漏了一些明显的东西,否则这有点疯狂。

    如果父文档不存在,则无法设置嵌套属性。由于
    地址
    不存在,因此无法在其内部设置属性
    。如果在创建项目时将
    address
    设置为空映射,则可以实现目标。然后,您可以使用以下参数对尚未存在的属性
    address.province
    进行条件更新

    var params = {
        TableName: 'Image',
        Key: {
            Id: 'dynamodb.png'
        },
        UpdateExpression: 'SET address.province = :ma',
        ConditionExpression: 'attribute_not_exists(address.province)',
        ExpressionAttributeValues: {
            ':ma': 'MA'
        },
        ReturnValues: 'ALL_NEW'
    };
    docClient.update(params, function(err, data) {
        if (err) ppJson(err); // an error occurred
        else ppJson(data); // successful response
    });
    

    顺便说一句,我不得不用省替换州,因为州是一个保留字。

    您可以通过两次往返来完成,第一次有条件地为
    地址设置一个空映射,如果它不存在,第二次设置
    州:

    db.update({
        UpdateExpression: 'SET #a = :value',
        ConditionExpression: 'attribute_not_exists(#a)',
        ExpressionAttributeValues: {
            ":value": {},
        },
        ExpressionAttributeNames: {
            '#a': 'address'
        }
    }, ...);
    
    然后:


    另一种完全不同的方法是,首先创建父文档时,只需创建
    地址
    节点。例如,假设您的哈希键为
    id
    ,您可以执行以下操作:

    db.put({
        Item: {
            id: 42,
            address: {}
        }
    }, ...);
    
    这将允许您简单地设置
    地址。将
    值声明为
    地址
    映射已经存在:

    db.update({
        UpdateExpression: 'SET #a.#b = :v',
        AttributeExpressionNames: {
            '#a': 'address',
            '#b': 'state'
        },
        AttributeExpressionValues: {
            ':v': 'whatever'
        }
    }, ...);
    

    一些kotlin代码可以递归地执行此操作,而不管它有多深。它将父路径的存在设置为条件,如果条件检查失败,则首先递归创建这些路径。它必须在库的包中,这样它才能访问那些包私有字段/类

    package com.amazonaws.services.dynamodbv2.xspec
    导入com.amazonaws.services.dynamodbv2.document.Table
    导入com.amazonaws.services.dynamodbv2.model.ConditionalCheckFailedException
    导入com.amazonaws.services.dynamodbv2.xspec.ExpressionSpecBuilder.attribute_存在
    fun Table.UpdateItemByPath(hashKeyName:String,hashKeyValue:Any,updateActions:List){
    val parentpath=updateActions.map{it.pathOperand.path.parent()}
    .filter{it.isNotEmpty()}
    .toSet()//删除重复项的步骤
    试一试{
    val builder=ExpressionSpecBuilder()
    updateActions.forEach{builder.addUpdate(it)}
    if(parentpath.isNotEmpty()){
    变量条件:条件=比较条件(“=”,文字操作数(真),文字操作数(真))
    parentpath.forEach{condition=condition.and(attribute_exists(it))}
    建造商。withCondition(条件)
    }
    this.updateItem(hashKeyName、hashKeyValue、builder.buildForUpdate())
    }捕获(e:ConditionalCheckFailedException){
    this.updateItemByPath(hashKeyName、hashKeyValue、parentPaths.map{M(it).set(mapOf())})
    this.updateItemByPath(hashKeyName、hashKeyValue、updateActions)
    }
    }
    private fun String.parent()=此.substringBeforeLast('.','')
    
    这是我在Typescript中编写的一个助手函数,它使用递归方法实现单级嵌套

    我将顶级属性称为列

    //usage
    await setKeyInColumn('customerA', 'address', 'state', "MA")
    
    //更新映射值以保存新的键值对。如果它不存在,它将创建一个顶级地址。
    静态异步setKeyInColumn(primaryKeyValue:string,colName:string,key:string,value:any,_doNotCreateColumn?:布尔){
    常量obj={};
    obj[key]=value;//创建类似{address:value}的嵌套值
    //某些条件取决于列是否已存在
    const ConditionExpression=\u doNotCreateColumn?未定义:`attribute\u not\u exists(${colName})`
    const AttributeValue=_doNotCreateColumn?值:obj;
    const UpdateExpression=\u doNotCreateColumn?`SET${colName}.${key}=:keyval`:`SET${colName}=:keyval`;
    试一试{
    常数更新图={
    TableName:TABLE_NAME,
    键:{Key:primaryKeyValue},
    UpdateExpression,
    表达式属性值:{
    “:keyval”:属性值
    },
    条件表达式,
    ReturnValues:“全新”,
    }
    const resp=wait docClient.update(updateParams.promise())
    if(resp&&resp[colName]){
    返回resp[colName];
    }
    }捕获(ex){
    //如果该列已存在,请重新运行并不要创建它
    如果(例如,代码=='ConditionalCheckFailedException'){
    返回此.setKeyInColumn(primaryKeyValue、colName、key、value、true)
    }
    console.log(“未能更新DynamoDB中的列”)
    控制台日志(ex);
    返回未定义
    }
    }
    
    您使用的是哪种语言sdk?您解决过这个问题吗?您可以绕过reserv
    //usage
    await setKeyInColumn('customerA', 'address', 'state', "MA")