有条件地将项目放入DynamoDB

问题描述

在我的Lambda函数中,仅当值尚未存在时,我才想有条件地将项目放入DynamoDB中。我看到多个不同的来源在他们使用此ConditionExpression的情况,但我无法弄清这是怎么回事。

body = await dynamo.put({
                    TableName: 'polit-stream',Item: {
                        urlPath: data.urlPath,},ConditionExpression: "attribute_not_exists(urlPath)"
                }).promise();

即使我的二级索引值(urlPath)已经存在,放置也将始终成功。

完整代码

const AWS = require('aws-sdk');
const crypto = require("crypto");
const dynamo = new AWS.DynamoDB.DocumentClient();

/**
 * Demonstrates a simple HTTP endpoint using API Gateway. You have full
 * access to the request and response payload,including headers and
 * status code.
 *
 * To scan a DynamoDB table,make a GET request with the TableName as a
 * query string parameter. To put,update,or delete an item,make a POST,* PUT,or DELETE request respectively,passing in the payload to the
 * DynamoDB API as a JSON body.
 */
exports.handler = async(event,context) => {

    let body;
    let statusCode = '200';
    const headers = {
        'Content-Type': 'application/json','Access-Control-Allow-Origin': '* '
    }

    const data = JSON.parse(event.body);
    const generateUUID = () => crypto.randomBytes(16).toString("hex");

    try {
        switch (event.httpMethod) {
            case 'DELETE':
                body = await dynamo.delete(JSON.parse(event.body)).promise();
                break;
            case 'GET':
                body = await dynamo.scan({
                        TableName: 'db',IndexName: 'urlPath',FilterExpression: "urlPath = :urlPath",ExpressionAttributeValues: {
                            ":urlPath": event.querystringparameters.urlPath
                        }
                    },function(data) {

                    }).promise();
                break;
            case 'POST':
                body = await dynamo.put({
                    TableName: 'db',Item: {
                        id: generateUUID(),name: data.name,date: data.date,place: data.place,goals: data.goals,type: data.type,org: data.org,email: data.email,urlPath: data.urlPath,createdAt: new Date().toISOString()
                    },ConditionExpression: "attribute_not_exists(urlPath)"
                }).promise();
                break;
            case 'PUT':
                body = await dynamo.update(JSON.parse(event.body)).promise();
                break;
            default:
                throw new Error(`Unsupported method "${event.httpMethod}"`);
        }
    }
    catch (err) {
        statusCode = '400';
        body = err.message;
    }
    finally {
        body = JSON.stringify(body);
    }

    return {
        statusCode,body,headers,};
};

解决方法

您的错误是您误解了ConditionExpression可以做什么。您完整的PutItem代码是:

               body = await dynamo.put({
                    TableName: 'db',Item: {
                        id: generateUUID(),name: data.name,date: data.date,place: data.place,goals: data.goals,type: data.type,org: data.org,email: data.email,urlPath: data.urlPath,createdAt: new Date().toISOString()
                    },ConditionExpression: "attribute_not_exists(urlPath)"
                }

您期望ConditionExpression: "attribute_not_exists(urlPath)"做什么?

您显然认为它会检查是否存在具有该值urlPath任何项目。不幸的是,但这不是此表达式的作用。它的作用是查看一个特定项目-具有相同密钥的项目(我不知道您的密钥是id?),然后检查该特定项目是否具有urlPath属性(具有任何值)。

如果urlPath是商品的钥匙,那么这项工作就如您希望的那样。如果urlPath是唯一的(根据您要执行的操作,看起来确实是唯一的),那么它实际上可以用作项目密钥。

,

为了使用ConditionExpression,您需要提供属性的名称和值。试试这个:

await dynamo.put({
  TableName: 'db',Item: {
    id: generateUUID(),createdAt: new Date().toISOString(),},ConditionExpression: "attribute_not_exists(#u) or (#u=:urlPath)",ExpressionAttributeNames: { "#u": "urlPath" },ExpressionAttributeValues: { ":urlPath": data.urlPath },});