如何正确使用list_append在DynamoDB中保持值唯一?

时间:2018-12-11 11:35:20

标签: node.js amazon-dynamodb

在下面的代码中,即使联系人属性已经存在,也会将其添加到contacts属性。但是我想防止重复,因为两次有相同的联系没有意义。 我试图使用包含没有成功。 您对我该如何处理有任何想法吗?

const contact = event.contactId
const params = {
    TableName,
    Key: {
        userId: event.userId
    },
    ReturnValues: 'UPDATED_NEW',
    UpdateExpression: 'set #contacts = list_append((if_not_exists(#contacts, :empty_list), :contact)',
    ExpressionAttributeNames: {
        '#contacts': 'contacts'
    },
    ExpressionAttributeValues: {
        ':contact': [contact],
        ':empty_list': []
    }
} // TODO: Must be unique IDs

dynamodb.update(params, (err, data) => {
    if (err) {
        console.log(err)
        callback(err)
    } else {
        console.log(data)
        const response = {
            statusCode: 200,
            message: "Successfully added contact " + contact,
            updatedContacts: data.Attributes.contacts
        }
        callback(null, response)
    }
})

1 个答案:

答案 0 :(得分:2)

据我所知,您只需要使用一次DynamoDB调用即可使用Set而不是List的联系人ID来实现所需的 。话虽如此,使用Set有两种方法可以完成此操作,如果可以在保存新联系人之前先进行阅读,则可以使用列表来完成此操作。

选项1

DynamoDB支持将ADD用于Set属性,并且Set将保证不存在重复的ID。您可以使用ADD默默成功,而不会导致使用此方法产生重复的联系人。

如果您使用ADD,则更新表达式为

ADD #contacts :contact

无论您的联系人ID是数字还是字符串,此方法都将起作用。

选项2

使用condition expression阻止添加联系人(如果已存在)。 DynamoDB具有contains(path, operand)函数,该函数支持String和StringSet属性。

您将使用与选项1中相同的更新表达式,并且条件表达式将为

attribute_not_exists(#contacts) OR NOT contains(#contacts, :contact)

此选项将让您知道该联系人已经存在,因为如果该联系人已经存在,您将收到DynamoDB的ConditionalCheckFailed响应。

选项3

首先从DynamoDB中读取当前的List联系人。在您的应用程序中验证您将不会添加重复项。如果新联系人是重复联系人,则您无事可做。如果联系人是重复联系人,则可以使用以下表达式保存更新的联系人列表

UpdateExpression: “SET #contacts = :updatedContacts”
ConditionExpression: "#contacts = :oldContacts”

在这种情况下,:oldContacts应该是您最初从DynamoDB中读取的列表。

此方法的缺点是对列表的并发更新可能导致有效更新失败。

选项4

这是所有方法中涉及最多的方法。您可以向表中的项目添加version属性,并且像选项3一样,您首先读取该项目,确认新联系人不是重复的,然后进行条件写入。但是,在这种情况下,您的条件写将包括

UpdateExpression: “SET #contacts = :updatedContacts, #version = :newVersion”,
ConditionExpression: “#version = :oldVersion”

这被称为Optimistic Locking。尽管不是JavaScript SDK的一部分,但在这种情况下,它很容易自行实现。

总结笔记

您应注意,选项3和4不适用于正在多个区域中同时更新的全局表。选项2可能无法通知您在相同条件下添加副本的尝试,但仍将保证不存在任何副本。 (Global Tables are eventually consistent between regions,因此条件表达式对于一个区域可能评估为true,但对于另一个区域则无效。)

最后,如果您想了解有关可在条件或更新表达式中使用的任何功能的更多详细信息,Comparison Operator and Function Reference可能会有所帮助。