Separate lists in Redis - redis

Im bulding a game server where i'm holding a list of connected users and at the same time a list of battles, those 2 lists are seperate.
I'm holding the battles data in Redis db, with battle id as the key,
could I use the connected user list in the same Redis db and get a list of the connected users in a elegant way while avoining battles data ?
I couldn't find a solution for that and currently holding the connected users in JS dictionary in my nodeJs server
UPDATE:
to clarify queries,
connected user object is -
connectedUser = {
nickname: string, (key)
socketId: string,
status: string,
rating: number
}
i would like to query the data with getUser(nickname) which will fetch a specific user and getAllUsers() to fetch all connected users.
as for match it includes all match data and stats
match = {
id: string, (key)
nicknameOne: string,
nicknameTwo: string,
...
}
on matches I query with id and believed it works well with hash table and hset and hget complexity wize.
as for queries on connected user, I wonder if using a simple js dictionary might provide with faster query results.
the js dictionary looks like that -
connectedUsers = {}
adding user -
user = {
key: nickname,
value: {
socketId: string,
status: string,
rating: number
}
}
while getting a specific user like that -
connectedUsers[nickname]
and iterating all this way -
for(let key in connectedUsers) {
//value - connectedUsers[key];
}

Nothing will beat the JS dictionary in terms of performance. Even with something as fast as Redis you're adding the overhead of interprocess communication (if hosted on the same machine) or network latencies.
If you want to use Redis for persistence, one way to store connected users would be to have a hash where keys are nicknames and values are user objects. You can do HGET users-key userId to get 1 user and HGETALL users-key to fetch all users.

Related

Making one column match the data of another column from a different table

I've made a Godot game and put it on my frontend, there are 2 things that happen database-wise when the user uses the site. Firstly he/she enters some details then they play the game and after either winning or losing the result is sent to the backend.
Currently I have two tables made in Postgres: Player and Play_Session; Player is made off the users details such as nickname etc whilst the Play_Session is made out of the game information such as the time it took for them to beat it, their reward etc. I'm trying to connect the two via Players ID and Play_Sessions userId I've made it so that if the two match everything will work as intended and if they do not that it is not a valid submissions. How would I go about doing this? I cannot use something as simple as a serial as if two players play at the same time things will fall apart and one might get the others data. Meaning I mostlikely need to alter my insert statement.
The code I have is the following:
export const createPlayer = async (email: string, nickname: string, address: string, number: bigint): Promise<QueryResult> => {
return await DbConnectionManager.pool.query(`INSERT INTO ${Table.Player} (${PlayerCols.Email}, ${PlayerCols.Nickname}, ${PlayerCols.Address}, ${PlayerCols.Number}) VALUES ($1,$2, $3, $4)`,
[email, nickname, address, number]);
}
----------
export const getPlayerData = () => {
return DbConnectionManager.pool.query(`SELECT ${PlayerCols.Email}, ${PlayerCols.Nickname}, ${PlayerCols.Address}, ${PlayerCols.Number}, ${SessionCols.Date}, ${SessionCols.Reward}, ${SessionCols.Time} FROM ${Table.Player} P JOIN ${Table.Session} ON P.${PlayerCols.Id} = ${SessionCols.UserId} WHERE ${SessionCols.Score} = 50 AND ${SessionCols.Date} = '2021-07-24'` )
}

Find namespace records in Redis

How do I find all the records in Redis?
USER_EXCHANGE = table
USER_ID = User ID (primary key)
UID = relationship
The key is stored with the following structure
USER_EXCHANGE:USER_ID:4030:UID:63867a4c6948e9405f4dd73bd9eaf8782b7a6667063dbd85014bd02046f6cc2e
I am trying to find all the records of the user 4030...
using (var redisClient = new RedisClient ())
{
List<object> ALL_UID = redisClient.Get<List<object>>("USER_EXCHANGE:USER_ID:4030:UID:*");
}
What am I doing wrong? Thank you all for your help.
Hi as you're trying to fetch all keys matching a pattern you should use KEYS.
GET won't match patterns. by will retrieve complete full names.
Caution this is a debug function and not a production function.
doc: https://redis.io/commands/keys
Production simple solution, recommanded for you is :
store a list of your key in a LIST
USER_EXCHANGE:USER_ID:4030 => [ uid1, uid2, uid3 ....]
get list of uids for a specific user ID by getting the list.
This is a good practice in REDIS.

Finding duplicate users in a user list (Asked in an Interview)

I was recently asked this in an interview for a SDE role.
Suppose you have a list of User objects
class User {
String userId;
String email;
String ip_addr;
}
where userId field is unique among all users, while ip_addr and email are not necessarily so.
and you know some users have more than one user account (if any two User objects share a common email OR an ip_addr, you classify them as belonging to the same user).
you are required to write a function, whose signature is given as:
List<List<User>> findDups(User[] userList) {
// code here
}
[EDIT] so for example, if there are 7 users, only 2 of which are unique, the function can return something like the following (not necessarily in this specific order):
{
{user1, ip1, email1},
{user5, ip5, email1},
{user24, ip5, email2}
},
{
{user2, ip2, email2},
{user7, ip2, email7},
{user8, ip2, email0},
{user19, ip19, email7}
}
here, in this first group, the first user (user1) is the same user as the second one (user5) as they share the same email address. We also know that the third user (user24) is also the same user as it shares the same ip address (ip5) as the second user in the list.
[/END EDIT]
what data structure would you use and what would be the time complexity of the proposed solution?
I tried to use disjoint set union (quick union), which would give me linear complexity, however the interviewer constantly tried to steer me away from that and said just the Collection API would be enough (Using Lists and Sets and maps).
What would be your approach and solution and the corresponding time complexity?

Problems understanding Redis ServiceStack Example

I am trying to get a grip on the ServiceStack Redis example and Redis itself and now have some questions.
Question 1:
I see some static indexes defined, eg:
static class TagIndex
{
public static string Questions(string tag) { return "urn:tags>q:" + tag.ToLower(); }
public static string All { get { return "urn:tags"; } }
}
What does that '>' (greater than) sign do? Is this some kind of convention?
Question 2:
public User GetOrCreateUser(User user)
{
var userIdAliasKey = "id:User:DisplayName:" + user.DisplayName.ToLower();
using (var redis = RedisManager.GetClient())
{
var redisUsers = redis.As<User>();
var userKey = redis.GetValue(userIdAliasKey);
if (userKey != null) return redisUsers.GetValue(userKey);
if (user.Id == default(long)) user.Id = redisUsers.GetNextSequence();
redisUsers.Store(user);
redis.SetEntry(userIdAliasKey, user.CreateUrn());
return redisUsers.GetById(user.Id);
}
}
As far as I can understand, first a user is stored with a unique id. Is this necessary when using the client (I know this is not for Redis necessary)? I have for my model a meaningful string id (like an email address) which I like to use. I also see a SetEntry is done. What does SetEntry do exactly? I think it is an extra key just to set a relation between the id and a searchable key. I guess this is not necessary when storing the object itself with a meaningful key, so user.id = "urn:someusername". And how is SetEntry stored as a Redis Set or just an extra key?
Question 3:
This is more Redis related but I am trying to figure out how everything is stored in Redis in order to get a grip on the example so I did:
Started redis-cli.exe in a console
Typed 'keys *' this shows all keys
Typed 'get id:User:DisplayName:joseph' this showed 'urn:user:1'
Typed 'get urn:user:1' this shows the user
Now I also see keys like 'urn:user>q:1' or 'urn:tags' if I do a 'get urn:tags' I get the error 'ERR Operation against a key holding the wrong kind of value'. And tried other Redis commands like smembers but I cannot find the right query commands.
Question 1: return "urn:tags>q:" + tag.ToLower(); gives you the key (a string) for a given tag; the ">" has no meaning for Redis, it's a convention of the developer of the example, and could have been any other character.
Question 3: use the TYPE command to determine the type of the key, then you'll find the right command in redis documentation to get the values.

REST APIs: Using Ids versus Actual Values in POST/PUT/GET

I am in a process of designing APIs to allow customers to manage their data using POST/PUT/GET.
One of the challenges for the API is that there are number of fields in entities that should have values from predetermined sets.
One of the approaches I see is to allow clients to pass IDs for each of the data filed(properties) and have a supplementary method to provide clients with available options for the data fields.
So the client interaction with the service will be:
Client: GET \Options (returns set of available options for each field)
Client: POST \Data (sends the DTO with set of IDs for each property this saves the data to the server)
Another option as I see is to let client to send actual values instead of IDs.
What approach do you recommend? And why?
Let clients pass the data as values BUT store the data as a foreign key on your server.
Let's say you design an API for adding cars and the car colour should be a value from a predetermined set.
HTTP requests:
GET cars/1
=> 200 OK
{ id: 1, name: "Ferrari", colour: "Red }
POST cars
{ name: Lamborghini, colour: "Blue" }
=> 201 Created (cars/2)
Database (just an example):
Table [Car]: #ID (Integer) , Name (Varchar) , ColourID (Integer)
Table [Colour] : #ID (Integer), Name(Varchar)
...where the Car.ColourID is a foreign key to your Colour.ID
The advantages are:
The API is easy to use
You still maintain the data constraint from predetermined sets, for example POSTing a car with colour: "Dog" should result in HTTP response with error information (e.g. Invalid colour).