I have a Node.js application with stores posts written by authors in a Redis database. The post is given a unique ID (the variable messageId), and two values are given: the message and the author. The first part of the code looks like so:
redisClient.hmset(messageId, "message", req.body.message, "author", req.body.author);
So far, so good. What I want to do is be able to retrieve the value of a specific key. I know I can use hgetall() to get all the keys and values for messageId, and I know I can use hkeys to get all the keys for messageId. If I know there will be a key called "message", how can I retrieve the value from message A) from the Redis client, and B) through Node.js?
NOTE: I have seen this: Redis + Node.js - how do I retrieve the values. It does not tell me what I need.
There is hget to retrieve a single value, and hmget to retrieve multiple values.
See Redis commands for hash. The node.js client should support them all.
Something like:
redisClient.hget(messageId, "message");
redisClient.hmget(messageId, ["message", "author"]);
Related
I have a chat module coded in Nodejs and Redis, which loads all the DB users into Redis and later retrieve them with the Key and Value, As what redis server is expected to do,
To store them I used "Key" as the User_ID with prefix and values in json as below,
entry.user_id = rows[i].user_id;
entry.uname = rows[i].uname.toString();
client.set('chat_userid_' + entry.user_id, JSON.stringify(entry));
This works fine, as long as we do searches for the user's data using only the User_ID. Sometimes I have to find user with the "name" as well, In this case, when we want to search via name, I had to do another key to the value list just for that search.
entry.user_id = rows[i].user_id;
entry.uname = rows[i].uname.toString();
client.set('chat_uname_' + entry.uname, JSON.stringify(entry));
As you can see above Data structure is very low performance and redundant, Is there a better data structure to store the user data in the Redis server, that we can get the same result as per the above use-case?
My table structure in DynamoDB looks like the following:
uuid (Primary Key) | ip | userAgent
From within a NodeJS function inside of lambda, I would like to get the uuid of an item whose ip and useragent match the information I provide.
Scan becomes less and less efficient and more expensive over time as millions of items are added to the table every week.
Here is the code I am using to try and accomplish this:
function tieDown(sIP, uA){
const userQuery = {
Key : {
"ip" : "192.168.0.1",
"userAgent" : "sample"
},
TableName: "mytable"
};
return ddb.get(userQuery, function(err, data){
if (err) console.log(err.stack);
}).promise();
}
When this code executes, the following error is thrown ValidationException: The provided key element does not match the schema.
So I guess my questions are:
Is it even possible to get one specific item based on non-primary attributes
Are there any issues with the code sample I provided that could lead to this error being thrown? (I'm using DocumentClient so no need to explicitly declare strings, numbers etc.
Thanks!
You cannot get a single item using the get operation without specifying the partition key, and sort key if you have one. Scans should be avoided in most cases. What you probably need is a Global Secondary Index that allows you to query by ip and userAgent. Keep in mind that the records on a GSI are not guaranteed unique, so you may get more than one result.
I'm using NodeJS and DynamoDB. I'm never used DynamoDB before, and primary a C# developer (where this would simply just be a .Where(x => x...) call, not sure why Amazon made it any more complicated then that). I'm trying to simply just query the table based on if an id starts with certain characters. For example, we have the year as the first 2 characters of the Id field. So something like this: 180192, so the year is 2018. The 20 part is irrelevant, just wanted to give a human readable example. So the Id starts with either 18 or 17 and I simply want to query the db for all rows that Id starts with 18 (for example, could be 17 or whatever). I did look at the documentation and I'm not sure I fully understand it, here's what I have so far that is just returning all results and not the expected results.
let params = {
TableName: db.table,
ProjectionExpression: "id,CompetitorName,code",
KeyConditionExpression: "begins_with(id, :year)",
ExpressionAttributeValues: {
':year': '18'
}
return db.docClient.scan(params).promise();
So as you can see, I'm thinking that this would be a begins_with call, where I look for 18 against the Id. But again, this is returning all results (as if I didn't have KeyConditionExpression at all).
Would love to know where I'm wrong here. Thanks!
UPDATE
So I guess begin_with won't work since it only works on strings and my id is not a string. As per commenters suggestion, I can use BETWEEN, which even that is not working either. I either get back all the results or Query key condition not supported error (if I use .scan, I get back all results, if I use .query I get the error)
Here is the code I'm trying.
let params = {
TableName: db.table,
ProjectionExpression: "id,CompetitorName,code",
KeyConditionExpression: "id BETWEEN :start and :end",
ExpressionAttributeValues: {
':start': 18000,
':end': 189999
}
};
return db.docClient.query(params).promise();
It seems as if there's no actual solution for what I was originally trying to do unfortunately. Which is a huge downfall of DynamoDB. There really needs to be some way to do 'where' using the values of columns, like you can in virtually any other language. However, I have to admit, part of the problem was the way that id was structured. You shouldn't have to rely on the id to get info out of it. Anyways, I did find another column DateofFirstCapture which using with contains (all the dates are not the same format, it's a mess) and using a year 2018 or 2017 seems to be working.
if you want to fetch data by id, add it as the partition key. If you want to get data by part of the string, you can use "begins with" on sort key.
begins_with (a, substr)— true if the value of attribute a begins with a particular substring.
source: https://docs.amazonaws.cn/en_us/amazondynamodb/latest/developerguide/Query.html
begins_with and between can only be used on sort keys.
For query you must always supply partition key.
So if you change your design to have unique partition key (or unique combo of partition/sort keys) and strings like 180192 as sort key you will be able to query begins_with(sortkey, ...).
I am trying to access session data from node.js that is stored in redis.
In the redis-cli I ran Keys * and returned
1) "sess:ZRhBJSVLjbNMc-qJptjiSjp8lQhXGGBb"
2) "sess:6p1EcGvJukTT26h88NqoTGdz2R4zr_7k"
If I then run GET I get back what looks like a hash
redis 127.0.0.1:6379> GET sess:ZRhBJSVLjbNMc-qJptjiSjp8lQhXGGBb
"{cookie:{originalMaxAge:null,expires:null,httpOnly:true,path:/},userKey:a92ca307-b315-44bc-aadf-da838d063c78,
authenticated:true,clientKey:1ccb5308-2a7e-4f49-bcdf-b2379de44541}"
If I try to get the value in userKey using
hget sess:oq6RW1zP7sfcZZc4wb1RHbti390FxL7- userKey
it returns
ERR Operation against a key holding the wrong kind of value
so I ran a TYPE check and found that it's not a hash but a string. I am a bit confused now as the whole thing looks like a hash and I cannot figure out how to return the values that I need as just calling get returns the whole thing.
Is there some other command I need to use to get the values?
Thanks
If you can GET aganist the key then it is not a hash because you would get ERR Operation against a key holding the wrong kind of value. And it was confirmed by yourserlf doing HGET and getting the error.
Probably that keys looks like a hash because (it is a hash but not redis hash datatype) it is the unique token that was issued to user in his session cookie in client. When user send this cookie to the server in every request the server can retrieve session info from redis using the cookie value as redis key.
The value is a string in JSON format. You have to retrieve the whole value and parse it; ussing JSON.parse in node.js could do the job. Once the value is parsed you have a JavaScript object which attributes can be access in standard way:
var sessionData = JSON.parse(JSONString);
console.log(sessionData.userKey)
It's a string
You can't get some session value directly, because it's serialized to some format(in this case, JSON)
If the session is written by node.js, you should use the same API to read.
If the session is written by other system, and you must parse it with node, you should just GET it, and json parse it(JSON.parse)
I have table created using map in cassandra, Now i am trying to read the table from node.js and it returns object for the map, can i get the item count in a map and loop through it to get the items in the map?
table script
create table workingteam (teamid bigint primary key, status map)
You did not post a lot of details. First you will need to study the object Cassandra sends you. Good way to start would be to convert it to the JSON format and dump to the output through log.
console.log("Cassandra sent: %j", object);
I'm guessing in this object you will find attributes like connection parameters, host, client etc, but also something iterative that will contain keys and values.