What are the right data-structures to model this relationship, taking advantage of TTL in Redis - database

We are newbie's to redis and are trying to model the below relationship where there is a userid which could have multiple jid's and each jid will have it's own expiry time and need's to be expired at that time automatically and removed and we need to ensure that there could only be 5 jid's associated with a userid at any given point of time
userid1 : { jid1 : 1551140357883,
jid2 : 1551140357882,
jid3 : 1551140357782,
jid4 : 1551140357782,
jid5 : 1551140357682 }
From the last requirement figured that that the sortedset zset might be a good fit with name of set being the userid and field being jid and score of field being expiration time lie below
zadd userid1 1551140357883 jid1
this help us to enforce the 5 jid's per userid by checking the zset but then we are stuck on how to delete the jid's on expiry as we can't set the TTL for each element of the set. Any help in pointing us in the right direction to use the right data-structure for this use case would be great
Note : we may not want to introduce a batch job at this time to delete the expired tokens, and all our queries to redis will be by userid

Related

Get value of unknown keys

This is my firebase database structure in the image :
I'll explain the structure aswell,
I have a forum, which people can post trades in.
Every post has some random user key as you can see in the picture.
Also every post has a list of items which the user wants to sell or buy ('have' or 'want', in the image).
the number of items in each trade can change from 1 to 10.
I want to fetch all of the forum posts of the users that are selling ( or buying ) with some item id.
For example : Get forum posts of users selling items with 'Id' of 'Some Item Name'
How do I do this? I can't seem to get reference to each item in the inventory
since you can't do multiple orderByChild.
If you think it's impossible with this DB structure, Please offer me an alternative.
I want to know whether I'm wasting my time with firebase and this is impossible to do :(
Please note that I have a lot of data in my DB so I can't just filter the posts on the client side.
Either you can change your database structure OR You can create a different node which can contain the metadata of all the "have" OR "want" items with the itemID, userID and "have" or "want" node child number(in this case it should be 0-9, as there are 10 items in each type). So whenever you are saving/deleting you data from "have" or "want" section you have to do the same operation in the other new metadata table also.
You can run your query on this node to get the desired item and then with the help of result data you get those particular items directly by creating a reference at runtime as you are having userId, have or want type, itemId.
your metadata should be something like.
metadata
|
|
+{randonId1}
|
|-type : "have" or "want"
|-userId : "randonId of user".(Kt0QclmY3.as shown in picture)
|-Id: "Breakout Type-S"
|-childOnNode: 0, (0-9)
+{randonId2}
|
|-type : "have" or "want"
|-userId : "randonId of user".(Kt0R48Cp..as shown in picture)
|-Id: "Breakout"
|-childOnNode: 0, (0-9)

How to retrieve the previous record in navision

I'm new to navision, and I need need to retrieve the previous record from a table because I need its records.
So my question is : how can I retrieve the record that's just before the one I'm working with?
explanation :
I'm seaching but can't really find what I need on google. I actually can't use .GET() as one of the fields in the primary key varies from record to record.
what I need to do is calculate the difference in a field form a record and the previous e.g :
curent record : total : 150
previous : total : 100
what I need to do is to retrieve the total of the previous record in order to store the difference in another record.
current record : difference : 50
NEXT(-1)
Are you banned by google and microsoft simultaneously?

How do I store this in Redis?

I have many products (product_id). Users (user_id) view the products.
I want to query which users viewed whatever product in the last 24 hours. (In other words, I want to keep a list of user_ids attached to that product_id...and when 24 hours is up for a user, that user pops off that list and the record disappears)
How do I store this in Redis? Can someone give me a high-level schema because I'm new in Redis.
For something similar I use a sorted set with values being user ids and score being the current time. When updating the set, remove older items with ZREMRANGEBYSCORE as well as updating the time score for the current user.
Update with code:
Whenever a new item is added:
ZREMRANGEBYSCORE recentitems 0 [DateTime.Now.AddMinutes(-10).Ticks]
ZADD recentitems [DateTime.Now.Ticks] [item.id]
To get the ids of items added in the last 10 minutes:
ZREVRANGEBYSCORE recentitems [DateTime.Now.Ticks] [DateTime.Now.AddMinutes(-10).Ticks]
Note that you could also use
ZREVRANGE recentitems 0 -1
if you don't mind that the set could include older items if nothing has been added recently.
That gets you a list of item ids. You then use GET/MGET/HGET/HMGET as appropriate to retrieve the actual items for display.
If you want redis keys to drop off automatically then you'll probably want to use a redis key for every user_id-to-product_id map. So, you would write by doing something like redis.set "user-to-products:user_id:product_id", timestamp followed by redis.expire "user-to-products:user_id:product_id" 86400 (24hrs, in seconds).
To retrieve the current list you should be able to do redis.keys "user-to-products:user_id:*"

Repeat Event Calendar based - Database Design

I have got similar question to: How to best handle exception to repeating calendar events.
My questions is regarding the database design.
I have some event running indefinitely however sometimes the end date is known. Lets say i am creating one event to take one medicine so i know when it is going to start but i don't know when it need to be stopped, it will depend on the progress and how the doctor advises.
Now the interesting bit is, though i will be taking medicine everyday at particular time, for some day it can CHANGE (Time, Dose etc).
So, i will have one table storing the medication name, dose, start date etc.
Questions:
1. Should there be physical record for each day [As its subject to change on particular date]. But there can be millions of record if we start to store for each date.
Alternatively, i can have exception for the date user is changing the details.
Or i can create record for 6 months and when the time will get closer either user can increase or system will increase automatically if the event is still going.
I wonder how Google calendar handles repeat indefinably.
Your suggestion will be appreciated.
Pankaj.
I'd make a table with various possible conditions:
table repetition (
event_id int foreign key,
first_date date not null,
last_date date not null,
day_period int null, -- 3 = every 3 days
day_of_month int null, -- 1..31
-- day_of_week int null, -- 0..6, if needed
-- whatever else
)
Now you can easily select events that happen today:
select event.*
from repetition
where
-- (day_of_week is null or day_of_week = :current_day_of_week) and
(day_of_month is null or day_of_month = :current_day_of_month) and
(day_period is null or (:current_date - first_date) mod day_period = 0) and
first_date <= :current_date and
last_date >= :current_date
join event on event.id = event_id
An index by (first_date, last_date) will make the query plan efficient enough (an index range scan).
To make the range 'indefinite', just put last_date far to the future, like year 3000.
To handle 'single' changes in events, you can add a change_of column to event table and make it refer back to event.id. For regular events, it is null. For change events, it stores the overriding information for the event pointed to by change_of. If you fetch two events for current day, and one of these has change_of pointing to another event, you use the data from the overriding event record, and ignore the record to which change_of refers. For a one-time change, last_date = first_date.
This also allows to add recurring changes, which may be useful (regular prescription every second day and a change every 14th day), and changes on changes, which you'll probably avoid by input logic or a trigger.
It seems to be it would be best to store the time for the next event and information about how often it should be repeated.
Example:
Next event: 2011-02-21 08:15
Repeats: Weekly (or any other format you deem appropriate)
"Next event" needs to be incremented when the time comes.
To check if the event is today you check if NOW = first part of "Next event"

Get "surrounding" rows in NHibernate query

I am looking for a way to retrieve the "surrounding" rows in a NHibernate query given a primary key and a sort order?
E.g. I have a table with log entries and I want to display the entry with primary key 4242 and the previous 5 entries as well as the following 5 entries ordered by date (there is no direct relation between date and primary key). Such a query should return 11 rows in total (as long as we are not close to either end).
The log entry table can be huge and retrieving all to figure it out is not possible.
Is there such a concept as row number that can be used from within NHibernate? The underlying database is either going to be SQlite or Microsoft SQL Server.
Edited Added sample
Imagine data such as the following:
Id Time
4237 10:00
4238 10:00
1236 10:01
1237 10:01
1238 10:02
4239 10:03
4240 10:04
4241 10:04
4242 10:04 <-- requested "center" row
4243 10:04
4244 10:05
4245 10:06
4246 10:07
4247 10:08
When requesting the entry with primary key 4242 we should get the rows 1237, 1238 and 4239 to 4247. The order is by Time, Id.
Is it possible to retrieve the entries in a single query (which obviously can include subqueries)? Time is a non-unique column so several entries have the same value and in this example is it not possible to change the resolution in a way that makes it unique!
"there is no direct relation between date and primary key" means, that the primary keys are not in a sequential order?
Then I would do it like this:
Item middleItem = Session.Get(id);
IList<Item> previousFiveItems = Session.CreateCriteria((typeof(Item))
.Add(Expression.Le("Time", middleItem.Time))
.AddOrder(Order.Desc("Time"))
.SetMaxResults(5);
IList<Item> nextFiveItems = Session.CreateCriteria((typeof(Item))
.Add(Expression.Gt("Time", middleItem.Time))
.AddOrder(Order.Asc("Time"))
.SetMaxResults(5);
There is the risk of having several items with the same time.
Edit
This should work now.
Item middleItem = Session.Get(id);
IList<Item> previousFiveItems = Session.CreateCriteria((typeof(Item))
.Add(Expression.Le("Time", middleItem.Time)) // less or equal
.Add(Expression.Not(Expression.IdEq(middleItem.id))) // but not the middle
.AddOrder(Order.Desc("Time"))
.SetMaxResults(5);
IList<Item> nextFiveItems = Session.CreateCriteria((typeof(Item))
.Add(Expression.Gt("Time", middleItem.Time)) // greater
.AddOrder(Order.Asc("Time"))
.SetMaxResults(5);
This should be relatively easy with NHibernate's Criteria API:
List<LogEntry> logEntries = session.CreateCriteria(typeof(LogEntry))
.Add(Expression.InG<int>(Projections.Property("Id"), listOfIds))
.AddOrder(Order.Desc("EntryDate"))
.List<LogEntry>();
Here your listOfIds is just a strongly typed list of integers representing the ids of the entries you want to retrieve (integers 4242-5 through 4242+5 ).
Of course you could also add Expressions that let you retrieve Ids greater than 4242-5 and smaller than 4242+5.
Stefan's solution definitely works but better way exists using a single select and nested Subqueries:
ICriteria crit = NHibernateSession.CreateCriteria(typeof(Item));
DetachedCriteria dcMiddleTime =
DetachedCriteria.For(typeof(Item)).SetProjection(Property.ForName("Time"))
.Add(Restrictions.Eq("Id", id));
DetachedCriteria dcAfterTime =
DetachedCriteria.For(typeof(Item)).SetMaxResults(5).SetProjection(Property.ForName("Id"))
.Add(Subqueries.PropertyGt("Time", dcMiddleTime));
DetachedCriteria dcBeforeTime =
DetachedCriteria.For(typeof(Item)).SetMaxResults(5).SetProjection(Property.ForName("Id"))
.Add(Subqueries.PropertyLt("Time", dcMiddleTime));
crit.AddOrder(Order.Asc("Time"));
crit.Add(Restrictions.Eq("Id", id) || Subqueries.PropertyIn("Id", dcAfterTime) ||
Subqueries.PropertyIn("Id", dcBeforeTime));
return crit.List<Item>();
This is NHibernate 2.0 syntax but the same holds true for earlier versions where instead of Restrictions you use Expression.
I have tested this on a test application and it works as advertised

Resources