node.js AWS dynamodb updateItem

Pan*_*ano 10 amazon-web-services node.js amazon-dynamodb

是否有办法使用updateItem实现以下几点:1.如果DynamoDB中不存在属性,则添加属性2.如果DynamoDB中存在属性,则更新属性3.如果属性未包含在属性中,请保留这些属性.参数.

下面是一个示例:这是DynamoDB中的对象:

{
    id: "1234",
    variable1: "hello",
    variable2: "world"
}
Run Code Online (Sandbox Code Playgroud)

这是我想要更新的输入:

{
    id: "1234",
    variable1: "hello2",
    variable23: "dog"  // the variable name "variable23" could be anything
}
Run Code Online (Sandbox Code Playgroud)

以下是我想要实现的DynamoDB中的更新项:

{
    id: "1234",
    variable1: "hello2",
    variable2: "world",
    variable23: "dog"
}
Run Code Online (Sandbox Code Playgroud)

"variable23"可以是任何变量名称作为输入.

请帮忙!我使用node.js,我真的很感激,如果有人能告诉我一些代码如何实现这一点.

谢谢!

the*_*tto 33

我认为有些例子有点令人困惑。如果我有下表列

ID  | Name | Age
Run Code Online (Sandbox Code Playgroud)

我想更新Name属性并保持Age属性不变。

const updateName = async () => {
  const aws = require('aws-sdk');
  const docClient = new aws.DynamoDB.DocumentClient();

  const newName = 'Bob';

  const params = {
    TableName: 'myTable',
    Key: {
      ID: 'myId',
    },
    UpdateExpression: 'set Name = :r',
    ExpressionAttributeValues: {
      ':r': newName,
    },
  };

  await docClient.update(params).promise();
}

updateName();
Run Code Online (Sandbox Code Playgroud)

这看起来更简单一些。

  • 这个例子让我终于明白了语法。谢谢。 (3认同)

小智 18

您可以动态更新属性。见下面的代码。

export const update = (item) => {
  console.log(item)
  const Item = {
    note: "dynamic",
    totalChild: "totalChild",
    totalGuests: "totalGuests"
  };
  let updateExpression='set';
  let ExpressionAttributeNames={};
  let ExpressionAttributeValues = {};
  for (const property in Item) {
    updateExpression += ` #${property} = :${property} ,`;
    ExpressionAttributeNames['#'+property] = property ;
    ExpressionAttributeValues[':'+property]=Item[property];
  }

  
  console.log(ExpressionAttributeNames);


  updateExpression= updateExpression.slice(0, -1);
  
  
   const params = {
     TableName: TABLE_NAME,
     Key: {
      booking_attempt_id: item.booking_attempt_id,
     },
     UpdateExpression: updateExpression,
     ExpressionAttributeNames: ExpressionAttributeNames,
     ExpressionAttributeValues: ExpressionAttributeValues
   };

   return dynamo.update(params).promise().then(result => {
       return result;
   })
   
}
Run Code Online (Sandbox Code Playgroud)


小智 17

这是一个更安全且最新的函数来实现此目的:

const {
  DynamoDBClient, UpdateItemCommand,
} = require('@aws-sdk/client-dynamodb');
const { marshall, unmarshall } = require('@aws-sdk/util-dynamodb');

const client = new DynamoDBClient({});

/**
 * Update item in DynamoDB table
 * @param {string} tableName // Name of the target table
 * @param {object} key // Object containing target item key(s)
 * @param {object} item // Object containing updates for target item
 */
const update = async (tableName, key, item) => {
  const itemKeys = Object.keys(item);

  // When we do updates we need to tell DynamoDB what fields we want updated.
  // If that's not annoying enough, we also need to be careful as some field names
  // are reserved - so DynamoDB won't like them in the UpdateExpressions list.
  // To avoid passing reserved words we prefix each field with "#field" and provide the correct
  // field mapping in ExpressionAttributeNames. The same has to be done with the actual
  // value as well. They are prefixed with ":value" and mapped in ExpressionAttributeValues
  // along witht heir actual value
  const { Attributes } = await client.send(new UpdateItemCommand({
    TableName: tableName,
    Key: marshall(key),
    ReturnValues: 'ALL_NEW',
    UpdateExpression: `SET ${itemKeys.map((k, index) => `#field${index} = :value${index}`).join(', ')}`,
    ExpressionAttributeNames: itemKeys.reduce((accumulator, k, index) => ({ ...accumulator, [`#field${index}`]: k }), {}),
    ExpressionAttributeValues: marshall(itemKeys.reduce((accumulator, k, index) => ({ ...accumulator, [`:value${index}`]: item[k] }), {})),
  }));

  return unmarshall(Attributes);
};
Run Code Online (Sandbox Code Playgroud)

  • AWS 开发人员应该为这个 API 感到羞耻。谢谢,成功了! (6认同)

Kha*_* T. 16

这正是AWS.DynamoDB.DocumentClient的update方法所做的.

已经有关于如何使用的一个示例代码update的方法在这里在Node.js的用于AWS SDK为JavaScript

例如:

'use strict';

const aws = require('aws-sdk');

// It is recommended that we instantiate AWS clients outside the scope of the handler 
// to take advantage of connection re-use.
const docClient = new aws.DynamoDB.DocumentClient();

exports.handler = (event, context, callback) => {
    const params = {
        TableName: "MYTABLE",
        Key: {
            "id": "1"
        },
        UpdateExpression: "set variable1 = :x, #MyVariable = :y",
        ExpressionAttributeNames: {
            "#MyVariable": "variable23"
        },
        ExpressionAttributeValues: {
            ":x": "hello2",
            ":y": "dog"
        }
    };

    docClient.update(params, function(err, data) {
        if (err) console.log(err);
        else console.log(data);
    });
};
Run Code Online (Sandbox Code Playgroud)

  • 对我来说似乎不优雅。对于简单的情况,我们不能只传递一个对象并以与 putItem 方法类似的方式更新参数吗?!对于其他情况UpdateExpression、ExpressionAttributes 等将是相关的 (6认同)
  • 您可以在示例中显示一些代码吗?我已经看到了这个示例,但仍然感到困惑。如果我有30个属性,那么是否需要为30个属性编写表达式?如果我有新属性怎么办?谢谢! (2认同)
  • 所以我应该循环遍历输入对象,将属性名称添加到“ExpressionAttributeNames”,将相应的值添加到“ExpressionAttributeValues”,然后生成一个表达式字符串放入UpdateExpression? (2认同)
  • 如果我是你并且我应该像在 DynamoDB 中的情况一样存储不可预测的数据,我会将它*原样*作为使用一个固定属性名称的单个 JSON 对象,并让后端应用程序解析 JSON 对象检索时。 (2认同)

Spa*_*ied 6

这里是我使用的批量更新功能,重点是可读性。

const documentClient = new AWS.DynamoDB.DocumentClient(options);

const update = async ({  tableName,  primaryKeyName,  primaryKeyValue,  updates }) => {
    const keys = Object.keys(updates)
    const keyNameExpressions = keys.map(name => `#${name}`)
    const keyValueExpressions = keys.map(value => `:${value}`)
    const UpdateExpression = "set " + keyNameExpressions
        .map((nameExpr, idx) => `${nameExpr} = ${keyValueExpressions[idx]}`)
        .join("; "),
    const ExpressionAttributeNames = keyNameExpressions
        .reduce((exprs, nameExpr, idx) => ({ ...exprs, [nameExpr]: keys[idx] }), {})
    const ExpressionAttributeValues = keyValueExpressions
        .reduce((exprs, valueExpr, idx) => ({ ...exprs, [valueExpr]: updates[keys[idx]] }), {})

    const params = {
        TableName: tableName,
        Key: { [primaryKeyName]: primaryKeyValue },
        UpdateExpression,
        ExpressionAttributeNames,
        ExpressionAttributeValues
    };
    return documentClient.update(params).promise();
}

// USAGE
let { ID, ...fields} = {
    ID: "1234",
    field1: "hello",
    field2: "world"
}

update('tableName', 'ID', ID, fields) 
Run Code Online (Sandbox Code Playgroud)


Dan*_*iel 5

这是一个实用方法来做到这一点:

update: async (tableName, item, idAttributeName) => {

    var params = {
        TableName: tableName,
        Key: {},
        ExpressionAttributeValues: {},
        ExpressionAttributeNames: {},
        UpdateExpression: "",
        ReturnValues: "UPDATED_NEW"
    };

    params["Key"][idAttributeName] = item[idAttributeName];

    let prefix = "set ";
    let attributes = Object.keys(item);
    for (let i=0; i<attributes.length; i++) {
        let attribute = attributes[i];
        if (attribute != idAttributeName) {
            params["UpdateExpression"] += prefix + "#" + attribute + " = :" + attribute;
            params["ExpressionAttributeValues"][":" + attribute] = item[attribute];
            params["ExpressionAttributeNames"]["#" + attribute] = attribute;
            prefix = ", ";
        }
    }

    return await documentClient.update(params).promise();
}
Run Code Online (Sandbox Code Playgroud)