I am using AWS Iot core and dynamodbv2 to store my mqtt message.
My table Primary partition key deviceId
and Rule query statement as
SELECT *, topic(2) AS deviceId FROM 'device/ '
.
The first message publish{"deviceId": "Name1","temperature":25}
.
The table store like:
deviceId temperature
Name1 25
When I publish the second message
{"deviceId": "Name1","setpoint":23}
,
It will replace the previous message.
deviceId setpoint
Name1 23
I want to publish message separately. Is it possible to keep the previous message and store the both message like that? Thanks.
deviceId temperature setpoint
Name1 25 23
CodePudding user response:
Looks like you are using the dynamoDB PutItem method, that replaces a item if the same primary key is found.
According the Aws DynamoDB docs the PutItem method:
Creates a new item, or replaces an old item with a new item (including all the attributes). If an item already exists in the specified table with the same primary key, the new item completely replaces the existing item. You can perform a conditional put (insert a new item if one with the specified primary key doesn't exist), or replace an existing item if it has certain attribute values.
To ensure that a new item does not replace an existing item, use a conditional put operation with Exists
set to false.
For understand how to do this using Node.js take a look here.
CodePudding user response:
From the tutorial you mentioned and the way the system behaves, it looks like the PutItem method is used to insert elements into DynamoDB. Meaning new items will overwrite old items if an item with the same primary key already exists.
The problem here is, that your deviceId
is a bad primary key as it is not unique. You expect to have more than one entry with primary key Name1
which is not possible. Instead, I suggest to adjust your SQL statement to get a unique key. This key could be generated with the timestamp() or traceid() functions of AWS IoT Core. Your SQL could the look ike this:
SELECT *,
topic(2) AS deviceId,
timestamp() as timestamp,
traceid() as traceId
FROM 'device/ '
Then you use the timestamp
or traceId
or a compound key made up of timestamp
deviceId
for instance as your primary key. The deviceId
can be used as the sort key. This is also how it was described in the tutorial
sample_time
is a primary key and describes the time the sample was recorded.device_id
is a sort key and describes the device that provided the sampledevice_data
is the data received from the device and formatted by the rule query statement
Be aware, that you cannot store the data like this
deviceId temperature setpoint
Name1 25 23
unless your MQTT message containts temperature and setpoint. Otherwise they will always be stored separately.
The only "workaround" to store the data as you described is to write a small lambda that uses PutItem to store the data if none exists and UpdateItem to add "setpoint" or "temperature" to an already existing item. You could, most likely, even do without PutItem as UpdateItem:
Edits an existing item's attributes, or adds a new item to the table if it does not already exist. You can put, delete, or add attribute values. You can also perform a conditional update on an existing item (insert a new attribute name-value pair if it doesn't exist, or replace an existing name-value pair if it has certain expected attribute values).
If you are fine with only keeping the latest value of "temperature" and "setpoint" this set up is fine. If you need to keep a history of how the "temperature" changed over time then you should either add a timestamp to your message or use the SQL timestamp()
function and use the timestamp as or as part of your primary key. In case you plan to have a lot, and I mean a lot, of devices sending their data to AWS IoT then the timestamp may not be good enough as a primary key and you need to have a compound made up by the timestamp and deviceId to keep it unique.
A great introduction on how DynamoDB works, partition keys, sort keys, indexes and more can be found in this video of Marcia Villalba.