为了更好地理解亚马逊的DynamoDB、Lambda函数和IAM角色(在这个问题中,我将坚持使用DynamoDB),我正在设置一个Linux设备来监听新的DynamoDB项目,并定期以声音读取其他函数添加的更新。我的目标是查询或扫描项目,从特定的时间戳(设备上次检查的时间)开始按升序返回这些项目。
以下是我目前使用的项目结构:
{
"id": {
"S": "1eb4520d44715b6daa5f9d907fe43aab" //md5sum of "time"
},
"message": {
"S": "I'm creating the audible reporting log now."
},
"status": {
"S": "working"
},
"time": {
"S": "1452297505" //timestamp: should probably add milliseconds for sake of unique "id"
}
}
"id"是分区键。"时间"是排序键。现在来看这个,我想我可能应该把"时间"设为一个数字,而不是字符串。。。
查询还是扫描?查询似乎是正确的排序选项,但它需要在查询中有一个特定的分区ID(至少在AWS网站查询工具中是这样),所以我可能添加错误了。扫描加载所有项目,我猜排序不是自动的,也不是一个选项(至少在AWS网站查询工具中没有)。我真的只想加载大于时间戳值的项目,排序。
我在想什么?我感谢事先的帮助。
更新
在对AWS-CLI和DynamoDB进行进一步的实验后,我最终使用了一个略有不同的解决方案。由于这是一个小规模的"helloworld"类型的项目,因此目前所有更新项都使用一个分区键"SFReporter"添加到同一个表中。如果我决定开始使用单独的查询和/或设备监控额外的"报告器"/服务更新,这可能会扩大。
{
"datetime": { //sort key
"S": "2016-01-11T05:15:02"
},
"message": {
"S": "It is all good."
},
"reporter": { //primary partition key
"S": "SF Reporter"
},
"status": {
"S": "ok"
}
}
JSON查询本身看起来像这样(缩写为node.js示例):
var AWS = require("aws-sdk");
AWS.config.credentials = new AWS.SharedIniFileCredentials({ profile: 'default' });
AWS.config.update({"region": "us-west-2"});
var docClient = new AWS.DynamoDB.DocumentClient();
var params = {
TableName: "spoken_reports",
KeyConditionExpression: "#reporter = :reporter and #datetime >= :datetime",
ExpressionAttributeNames:{
"#reporter": "reporter",
"#datetime": "datetime"
},
ExpressionAttributeValues: {
":reporter":"SF Reporter",
":datetime":"2016-01-11T05:15:02"
}
};
docClient.query(params, onUpdatesReceived);
var onUpdatesReceived = function(err, data) {
if (err) {
console.log(err, err.stack);
} else {
console.log(data);
}
}
查询获取按字符串时间戳排序的最新更新(在本例中默认为升序)。这允许进行一些扩展,因为我可以让多个设备检查同一个表中的最新更新。我会创建一个定时查询/函数来偶尔清除旧的更新,以保持轻松。
非常简单的方法:
您应该设置一个全局辅助索引,并将"isNew"作为其主/哈希键,将时间戳作为范围键。
创建条目时,将isNew
标记为UUID或其他什么。这将使表项项目进入索引。
当您需要检查数据时,scan
是辅助索引-该索引将只具有新的结果。然后,updateItem
在表本身中读取的项,以删除该项上的isNew
键。该项将从辅助索引中删除,因此不会再次读取。
如果你坚持这种表设计,扫描整个表是你唯一的选择,原因你已经提到:为了查询,你需要一个分区键,这是你的设备事先无法知道的。
我想到了另一个解决方案:
- 假设您当前的表名为T1。创建另一个表T2,它将
deviceID
作为分区键,timestamp
作为排序键 - 您在T1的流上定义了一个AWS Lambda函数,该函数在任何更新时都会在T2中推送该行,每个设备一个
- 现在,每当你的任何设备醒来时,它都会用自己的设备id查询(而不是扫描)T2。处理所有行并删除它们
换句话说,T2将始终具有给定设备尚未处理的所有行。