node.js AWS dynamodb updateItem

时间:2017-01-28 22:15:12

标签: node.js amazon-web-services amazon-dynamodb

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

这是一个例子: 这是DynamoDB中的对象:

{
    id: "1234",
    variable1: "hello",
    variable2: "world"
}

以下是我想要更新的输入:

{
    id: "1234",
    variable1: "hello2",
    variable23: "dog"  // the variable name "variable23" could be anything
}

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

{
    id: "1234",
    variable1: "hello2",
    variable2: "world",
    variable23: "dog"
}

“variable23”可以是任何变量名称作为输入。

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

谢谢!

8 个答案:

答案 0 :(得分:11)

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

已经有一个示例代码,介绍如何在Node.js中使用update方法here用于AWS SDK for 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);
    });
};

答案 1 :(得分:9)

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

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;
   })
   
}

答案 2 :(得分:4)

这是一种实用的方法:

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();
}

答案 3 :(得分:3)

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

ID  | Name | Age

我想更新 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();

这看起来更简单一些。

答案 4 :(得分:3)

这里有一个更安全和最新的函数来实现这一点:

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);
};

答案 5 :(得分:1)

对于这里解决方案的速度模板版本的任何人,他们在他们的文档中记录了一些东西,我花了一段时间才找到,所以如果对其他人有帮助,这里是一个链接

https://docs.aws.amazon.com/appsync/latest/devguide/resolver-mapping-template-reference-dynamodb.html#id4 在“选项 2”下

答案 6 :(得分:0)

很抱歉迟到了,但这是 google 上的 [非 aws-documentation] 最高结果,并且没有回答我的用例 - 使用 DocumentClient 而不使用 [un] marshalling 并具有动态项目。所以我想放弃我的 2 美分,并尝试通过合并来自 @khalid-t 的已批准答案和来自 @Arno 的答案来提供帮助。

'use strict';
const aws = require('aws-sdk');
const docClient = new aws.DynamoDB.DocumentClient();
const updateItem = async (pk, item) => await docClient.update({
    TableName,
    Key: {pk},
    UpdateExpression: 'set ' + Object.keys(item).map(k => `#${k} = :${k}`).join(', '),
    ExpressionAttributeNames: Object.entries(item).reduce((acc, cur) => ({...acc, [`#${cur[0]}`]: cur[0]}), {}),
    ExpressionAttributeValues: Object.entries(item).reduce((acc, cur) => ({...acc, [`:${cur[0]}`]: cur[1]}), {}),
}).promise();

答案 7 :(得分:0)

我使用 dynamo DB 客户端制作的:

updateItem(item: { [key: string]: any }) {
  const marshaledItem = marshall(item, { removeUndefinedValues: true, });
  const marshaledItemKeys = Object.entries(marshaledItem);

  const params: UpdateItemInput = {
    TableName: this.tableName,
    UpdateExpression: 'set',
    ExpressionAttributeNames: {},
    ExpressionAttributeValues: {},
    Key: marshall({ pk: item.pk, sk: item.sk })
  };

  marshaledItemKeys.forEach(([key, value] ) => {
    if (key === 'sk' || key === 'pk') return;
    params.UpdateExpression += ` #${key} = :${key},`;
    params.ExpressionAttributeNames[`#${key}`] = key;
    params.ExpressionAttributeValues[`:${key}`] = value;
  })

  params.UpdateExpression = params.UpdateExpression.slice(0, -1);
  console.log('REVEAL YOURSELF, YOU MIGHTY BUG: ', params);

  return this.dynamoDbClient.send(new UpdateItemCommand(params));
}

这对我来说非常有效。 Marshall 和 unmarshall 是以下内容的一部分:

import { marshall, unmarshall } from '@aws-sdk/util-dynamodb';

如果我传递 undefined 的值,它将从查询中删除这些值。如果我保留它们 null,它会用 null

覆盖它们

这是我如何使用它的示例:

async updatePatient(data: PutPatientData): Promise<DBPatient> {
    const {
      pk,
      sk,
      databaseId,
      betterPatientId,
      clinicientPatientId,
      latestClinicientCaseId,
      firstName,
      lastName,
      email,
      birthday,
      gender,
      phone,
    } = data;

    if (!pk && !databaseId) throw Error('Please provide PK or databaseId');
    if (!sk && !betterPatientId) throw Error('Please provide SK or betterPatientId');

    const patientRequestData = {
      pk: pk || `DATABASE#${databaseId}`,
      sk: sk || `PATIENT#${betterPatientId}`,
      itemType: 'Patient',
      lastUpdatedAt: DateTime.now().toString(),
      latestClinicientCaseId: latestClinicientCaseId || undefined,
      clinicientPatientId: clinicientPatientId || undefined,
      firstName: firstName || undefined,
      lastName: lastName || undefined,
      email: email || undefined,
      birthday: birthday || undefined,
      gender: gender || undefined,
      phone: phone || undefined,
      betterPatientId: betterPatientId || undefined,
    } as DBPatient;
    // Composite key
    if (email && birthday) patientRequestData['itemId'] = `PATIENT#${email}#${birthday}`;
        console.log('PATIENT UPDATE', patientRequestData)
    return this.updateItem(patientRequestData).then(() => patientRequestData);
}