DynamoDB.DocumentClient 具有动态属性和原子计数器
DynamoDB.DocumentClient With Dynamic Attributes and Atomic Counter
我正在处理一个用例,其中 dynamoDB 更新应该:
- 动态更新(如果存在则更新,如果不存在则插入)项目,而不对项目的组件进行硬编码。
- 为简单起见,使用 DynamoDB 文档客户端
- 并在同一个原子操作中,更新一个简单的计数器
我从 的 Daniel Barrel 的一个优秀的实用方法开始,它提供了一个通用的实用方法来更新动态值,但没有原子计数器。
我试图通过在加载动态值后将计数器及其增量器添加到参数对象中来添加原子计数器功能,但是在更新时我在计数器中得到一个静态值而不是递增的值每次调用一个。
这是哪里出错了?我使用 table 名称、动态 javascript 对象和包含哈希和排序键的数组调用修改后的更新函数:
await update(tableName, jsonObjectToStore, ['myHashKey', 'mySortKey'])
修改后的更新方法没有像我想要的那样递增,是:
async function update (tableName, item, idAttributeNames) {
var params = {
TableName: tableName,
Key: {},
ExpressionAttributeValues: {},
ExpressionAttributeNames: {},
UpdateExpression: "",
ReturnValues: "UPDATED_NEW"
};
for (const attname of idAttributeNames) {
params["Key"][attname] = item[attname];
}
let prefix = "set ";
let attributes = Object.keys(item);
for (let i=0; i<attributes.length; i++) {
let attribute = attributes[i];
if (!idAttributeNames.includes(attribute)) {
params["UpdateExpression"] += prefix + "#" + attribute + " = :" + attribute;
params["ExpressionAttributeValues"][":" + attribute] = item[attribute];
params["ExpressionAttributeNames"]["#" + attribute] = attribute;
prefix = ", ";
}
}
// Add the counter
params["UpdateExpression"] += ", #nImports = :nImports + :incr";
console.log(params["UpdateExpression"])
console.log(params["ExpressionAttributeValues"])
params["ExpressionAttributeValues"][":incr"] = 1;
params["ExpressionAttributeValues"][":nImports"] = 0;
console.log(params["ExpressionAttributeValues"])
console.log(params["ExpressionAttributeNames"])
params["ExpressionAttributeNames"]["#nImports"] = 'nImports'
console.log(params["ExpressionAttributeNames"])
await docClient.update
return await docClient.update(params).promise();
}
与 AWS Support 合作寻找合理的解决方案。他们也不确定如何使用 ddb 文档客户端(相对于具有许多文档示例的低级客户端)进行原子计数器,但建议使用 ADD 命令,该命令具有对数字字段进行原子更新的副作用。
因此,在下面的示例中,我们从要存储的对象构建动态更新,然后在更新表达式中附加 ADD 语句(没有逗号!),并向 nImports 的 ExpressionAttributeValues 添加实际上是一个数字增量器。像这样,这应该是一个完整的工作 lambda 示例。有一些 console.log 语句可以说明正在发生的事情:
const AWS = require('aws-sdk');
const docClient = new AWS.DynamoDB.DocumentClient();
async function update (tableName, item, idAttributeNames) {
var params = {
TableName: tableName,
Key: {},
ExpressionAttributeValues: {},
ExpressionAttributeNames: {},
UpdateExpression: "",
ReturnValues: "UPDATED_NEW"
};
for (const attname of idAttributeNames) {
params["Key"][attname] = item[attname];
}
let prefix = "set ";
let attributes = Object.keys(item);
for (let i=0; i<attributes.length; i++) {
let attribute = attributes[i];
if (!idAttributeNames.includes(attribute)) {
params["UpdateExpression"] += prefix + "#" + attribute + " = :" + attribute;
params["ExpressionAttributeValues"][":" + attribute] = item[attribute];
params["ExpressionAttributeNames"]["#" + attribute] = attribute;
prefix = ", ";
}
}
console.log('params before adding atomic counter is:', params)
// Add the counter using the ADD syntax
params["UpdateExpression"] += " ADD #nImports :nImports"
params["ExpressionAttributeValues"][":nImports"] = 1;
params["ExpressionAttributeNames"]["#nImports"] = 'nImports'
console.log('params after adding atomic counter is:', params)
try {
const result = await docClient.update(params).promise();
console.log('after await, result is ', result);
return result;
} catch (err) {
console.log('err is ', err)
}
};
exports.handler = async (event) => {
const item = {title: 'sometitle', site_url: "www.amazon.com", key: "G"};
const body = await update('test_table', item, ['title', 'site_url']);
const response = {
statusCode: 200,
body: JSON.stringify(body),
};
return response;
}
AWS 的好心人做了更多的挖掘,还指出了初始代码中的一个错误,在更正后,应该使用 SET 运算符按需要递增。
基本上,原始代码没有正确地针对增量变量。所以我们添加增量变量的更正版本应该是:
console.log('params before adding atomic counter is:', params)
// Add the counter
params["UpdateExpression"] += ", #nImports = #nImports + :incr";
params["ExpressionAttributeValues"][":incr"] = 1;
//params["ExpressionAttributeValues"][":nImports"] = 0;
params["ExpressionAttributeNames"]["#nImports"] = 'nImports'
console.log('params after adding atomic counter is:', params)```
I'm sticking with the original ADD answer because I like the differentiation it gives over the properties inserted by the SET, but both seem valid and I wanted to include the correction as well
我正在处理一个用例,其中 dynamoDB 更新应该:
- 动态更新(如果存在则更新,如果不存在则插入)项目,而不对项目的组件进行硬编码。
- 为简单起见,使用 DynamoDB 文档客户端
- 并在同一个原子操作中,更新一个简单的计数器
我从
我试图通过在加载动态值后将计数器及其增量器添加到参数对象中来添加原子计数器功能,但是在更新时我在计数器中得到一个静态值而不是递增的值每次调用一个。
这是哪里出错了?我使用 table 名称、动态 javascript 对象和包含哈希和排序键的数组调用修改后的更新函数:
await update(tableName, jsonObjectToStore, ['myHashKey', 'mySortKey'])
修改后的更新方法没有像我想要的那样递增,是:
async function update (tableName, item, idAttributeNames) {
var params = {
TableName: tableName,
Key: {},
ExpressionAttributeValues: {},
ExpressionAttributeNames: {},
UpdateExpression: "",
ReturnValues: "UPDATED_NEW"
};
for (const attname of idAttributeNames) {
params["Key"][attname] = item[attname];
}
let prefix = "set ";
let attributes = Object.keys(item);
for (let i=0; i<attributes.length; i++) {
let attribute = attributes[i];
if (!idAttributeNames.includes(attribute)) {
params["UpdateExpression"] += prefix + "#" + attribute + " = :" + attribute;
params["ExpressionAttributeValues"][":" + attribute] = item[attribute];
params["ExpressionAttributeNames"]["#" + attribute] = attribute;
prefix = ", ";
}
}
// Add the counter
params["UpdateExpression"] += ", #nImports = :nImports + :incr";
console.log(params["UpdateExpression"])
console.log(params["ExpressionAttributeValues"])
params["ExpressionAttributeValues"][":incr"] = 1;
params["ExpressionAttributeValues"][":nImports"] = 0;
console.log(params["ExpressionAttributeValues"])
console.log(params["ExpressionAttributeNames"])
params["ExpressionAttributeNames"]["#nImports"] = 'nImports'
console.log(params["ExpressionAttributeNames"])
await docClient.update
return await docClient.update(params).promise();
}
与 AWS Support 合作寻找合理的解决方案。他们也不确定如何使用 ddb 文档客户端(相对于具有许多文档示例的低级客户端)进行原子计数器,但建议使用 ADD 命令,该命令具有对数字字段进行原子更新的副作用。
因此,在下面的示例中,我们从要存储的对象构建动态更新,然后在更新表达式中附加 ADD 语句(没有逗号!),并向 nImports 的 ExpressionAttributeValues 添加实际上是一个数字增量器。像这样,这应该是一个完整的工作 lambda 示例。有一些 console.log 语句可以说明正在发生的事情:
const AWS = require('aws-sdk');
const docClient = new AWS.DynamoDB.DocumentClient();
async function update (tableName, item, idAttributeNames) {
var params = {
TableName: tableName,
Key: {},
ExpressionAttributeValues: {},
ExpressionAttributeNames: {},
UpdateExpression: "",
ReturnValues: "UPDATED_NEW"
};
for (const attname of idAttributeNames) {
params["Key"][attname] = item[attname];
}
let prefix = "set ";
let attributes = Object.keys(item);
for (let i=0; i<attributes.length; i++) {
let attribute = attributes[i];
if (!idAttributeNames.includes(attribute)) {
params["UpdateExpression"] += prefix + "#" + attribute + " = :" + attribute;
params["ExpressionAttributeValues"][":" + attribute] = item[attribute];
params["ExpressionAttributeNames"]["#" + attribute] = attribute;
prefix = ", ";
}
}
console.log('params before adding atomic counter is:', params)
// Add the counter using the ADD syntax
params["UpdateExpression"] += " ADD #nImports :nImports"
params["ExpressionAttributeValues"][":nImports"] = 1;
params["ExpressionAttributeNames"]["#nImports"] = 'nImports'
console.log('params after adding atomic counter is:', params)
try {
const result = await docClient.update(params).promise();
console.log('after await, result is ', result);
return result;
} catch (err) {
console.log('err is ', err)
}
};
exports.handler = async (event) => {
const item = {title: 'sometitle', site_url: "www.amazon.com", key: "G"};
const body = await update('test_table', item, ['title', 'site_url']);
const response = {
statusCode: 200,
body: JSON.stringify(body),
};
return response;
}
AWS 的好心人做了更多的挖掘,还指出了初始代码中的一个错误,在更正后,应该使用 SET 运算符按需要递增。
基本上,原始代码没有正确地针对增量变量。所以我们添加增量变量的更正版本应该是:
console.log('params before adding atomic counter is:', params)
// Add the counter
params["UpdateExpression"] += ", #nImports = #nImports + :incr";
params["ExpressionAttributeValues"][":incr"] = 1;
//params["ExpressionAttributeValues"][":nImports"] = 0;
params["ExpressionAttributeNames"]["#nImports"] = 'nImports'
console.log('params after adding atomic counter is:', params)```
I'm sticking with the original ADD answer because I like the differentiation it gives over the properties inserted by the SET, but both seem valid and I wanted to include the correction as well