Given I have a list stored in a key "A", how can I duplicate that list in a different key "B"?
I know that for non list values, I can "get", and then "set". But for lists when I try to get it, I see the WRONGTYPE operation error.
Redis enables 5 different data structures, such as:
Key values
Strings
Hashs
Lists
Sets
Each of the data structure has its own commands.
In order to get the current list you should use the LRANGE command.
The prefix L referes to the List data structure.
(Redis Set data structure has a related command to range by using SETRANGE)
If you read the Redis LRANGE documentation you will understand how to use it.
Here is the brief code you may use:
LRANGE mylist 0 -1
Where mylist is the list you get the values from.
The offsets start and stop are zero-based indexes, with 0 being the
first element of the list (the head of the list), 1 being the next
element and so on.
-1 is used to describe the last element in the list.
Now you should use the LPUSH or RPUSH depends on the list side you wish to insert the old elements into the new list.
You should use LRANGE to get all elements of the first list, then use LPUSH or RPUSH to put these elements into the second list.
Another way to duplicate a key's value, regardless the data structure, is to DUMP it and then RESTORE it into the new key. In most cases this approach is also the quickest.
Related
I have many different keys. some start with "user USERNAME" and many others.
is there a way to get a random key from the "user *" ?
if so, how can i get like 5 different users?
If you put all the usernames into a Redis set, then you could use the SRANDMEMBER command to randomly gets usernames from the set. Example from the documentation:
redis> SADD myset one two three
(integer) 3
redis> SRANDMEMBER myset
"three"
redis> SRANDMEMBER myset 2
1) "three"
2) "two"
The set seems to be the only Redis data type that can return random elements from the collection. You might have to process your data a little differently to do this.
You can definitely use a Set and store all your "user*" key names in it, as suggested by #Sunil D.
Alternatively, you could use a dedicated Redis database for your "user*" keys and then use the RANDOMKEY command to fetch keys from it. The nice thing about this is that you don't have to manage the Set of key names (i.e. add and remove to it whenever a key is created or deleted, respectively).
Note, however, that with both approaches, you'll have to check that the result you got wasn't returned earlier after each call to SRANDMEMBER or RANDOMKEY since both do not ensure that you'll get a different answer each time you invoke it.
On my current project I'm implementing autocompletion service on top of Redis, for it I use such approach (this article describes it more widely):
1) for storing dump of the data I have hash in which I put searchable objects as a values, for instance
HSET data 1 "{\"name\":\"Kill Bill\",\"year\":2003}"
HSET data 2 "{\"name\":\"King Kong\",\"year\":2005}"
2) for storing all possible sequences of input characters (that I generate in advance) which could be used in search I use sorted sets, like
ZADD search:index:k 0 1
ZADD search:index:ki 0 1
ZADD search:index:kil 0 1
ZADD search:index:kill 0 1
Where value stored in sorted set (in my example '1') is key for data from hash. So, for searching some data (for example where name started with 'ki') we need to make two steps:
data_keys = REDIS.zrevrange('search:index:ki', 0, -1)
matching_data = REDIS.hmget(data, *data_keys)
The issue I tried to solve - how automatically remove all data from sorted sets related to hash values when I removed it? In relational databases I can use cascade deletion for such cases, but how can I handle it in Redis?
Your design appears awkward to me, I'm unsure what you're actually trying to do with Redis and perhaps that could be the topic of another question.
That said, to address your question, Redis does offer a "cascading delete"-like behavior. Instead, if you're deleting hash "1", iterate the prefix and ZREM it from the relevant sorted sets.
Note: do not use a Lua script for this task, as it will generate key names (i.e. sorted sets by prefix) and that is against the recommendations (will not work on a cluster)
In redis I store objects in a sorted set.
In my solution, it's important to be able to run a ranged query by dates, so I store the items with the score being the timestamp of each items, for example:
# Score Value
0 1443476076 {"Id":"92","Ref":"7ADT","DTime":1443476076,"ATime":1443901554,"ExTime":0,"SPName":"7ADT33CFSAU6","StPName":"7ADT33CFSAU6"}
1 1443482969 {"Id":"11","Ref":"DAJT","DTime":1443482969,"ATime":1443901326,"ExTime":0,"SPName":"DAJTJTT4T02O","StPName":"DAJTJTT4T02O"}
However, in other situations I need to find a single item in the set based on it's ID.
I know I can't just query this data structure as if it were a nosql db, but I tried using ZSCAN, which didn't work.
ZSCAN MySet 0 MATCH Id:92 count 1
It returns; "empty list or set"
Maybe I need to serialize different?
I have serialized using Json.Net.
How, if possible, can I achieve this; using dates as score and still be able to lookup an item by it's ID?
Many thanks,
Lars
Edit:
Assume it's not possible, but any thoughts or inputs are welcome:
Ref: http://openmymind.net/2011/11/8/Redis-Zero-To-Master-In-30-Minutes-Part-1/
In Redis, data can only be queried by its key. Even if we use a hash,
we can't say get me the keys wherever the field race is equal to
sayan.
Edit 2:
I tried to do:
ZSCAN MySet 0 MATCH *87*
127.0.0.1:6379> ZSCAN MySet 0 MATCH *87*
1) "192"
2) 1) "{\"Id\":\"64\",\"Ref\":\"XQH4\",\"DTime\":1443837798,\"ATime\":1444187707,\"ExTime\":0,\"SPName\":\"XQH4BPGW47FM\",\"StPName\":\"XQH4BPGW47FM\"}"
2) "1443837798"
3) "{\"Id\":\"87\",\"Ref\":\"5CY6\",\"DTime\":1443519199,\"ATime\":1444172326,\"ExTime\":0,\"SPName\":\"5CY6DHP23RXB\",\"StPName\":\"5CY6DHP23RXB\"}"
4) "1443519199"
And it finds the desired item, but it also finds another one with an occurance of 87 in the property ATime. Having more unique, longer IDs might work this way and I would have to filter the results in code to find the one with the exact value in its property.
Still open for suggestions.
I think it's very simple.
Solution 1(Inferior, not recommended)
Your way of ZSCAN MySet 0 MATCH Id:92 count 1 didn't work out because the stored string is "{\"Id\":\"92\"... not "{\"Id:92\".... The string has been changed into another format. So try to use MATCH Id\":\"64 or something like that to match the json serialized data in redis. I'm not familiar with json.net, so the actual string leaves for you to discover.
By the way, I have to ask you did ZSCAN MySet 0 MATCH Id:92 count 1 return a cursor? I suspect you used ZSCAN in a wrong way.
Solution 2(Better, strongly recommended)
ZSCAN is good when your sorted set is not large and you know how to save network roundtrip time by Redis' Lua transaction. This still make "look up by ID" operation O(n). Therefore, a better solution is to change you data model in the following way:
change sorted set
from
# Score Value
0 1443476076 {"Id":"92","Ref":"7ADT","DTime":1443476076,"ATime":1443901554,"ExTime":0,"SPName":"7ADT33CFSAU6","StPName":"7ADT33CFSAU6"}
1 1443482969 {"Id":"11","Ref":"DAJT","DTime":1443482969,"ATime":1443901326,"ExTime":0,"SPName":"DAJTJTT4T02O","StPName":"DAJTJTT4T02O"}
to
# Score Value
0 1443476076 Id:92
1 1443482969 Id:11
Move the rest detailed data in another set of hashes type keys:
# Key field-value field-value ...
0 Id:92 Ref-7ADT DTime-1443476076 ...
1 Id:11 Ref-7ADT DTime-1443476076 ...
Then, you locate by id by doing hgetall id:92. As to ranged query by date, you need do ZRANGEBYSCORE sortedset mindate maxdate then hgetall every id one by one. You'd better use lua to wrap these commands in one and it will still be super fast!
Data in NoSql database need to be organized in a redundant way like above. This may make some usual operation involve more than one commands and roundtrip, but it can be tackled by redis's lua feature. I strongly recommend the lua feature of redis, cause it wrap commands into one network roundtrip, which are all executed on the redis-server side and is atomic and super fast!
Reply if there's anything you don't know
If I have a series of keys representing bitmaps in Redis, how can I get a list of all keys whose n bit value is equal to 1. For example, I have the following bitmaps:
keyname:20140418:item1: 000111...0010
keyname:20140418:item2: 000101...1010
keyname:20140418:item3: 100011...0010
I want to get the list of all items whose first value is 0 which would result in:
keyname:20140418:item1
keyname:20140418:item2
In Redis, always prepare your data in such a way that retrieval is easy and most of all scalable.
When storing the data, accompany the SET with a ZADD zerostartingbitmaps [unixtimestamp] [linkedkey]
To fix all your data and fill the Sorted Set, use SCAN and bitwise operations.
Hope this helps, TW
I was wondering if something like this is possible. I am working with a redis list, and was wondering if I could move a item from the middle of a list to the top of a list like this:
LPUSH mylist "This"
LPUSH mylist "is"
LPUSH mylist "a"
LPUSH mylist "Test"
Somehow Move "a" to top
LRANGE mylist
1. "a"
2. "This"
3. "Is"
4."Test"
Thanks for the help!
Redis Lists are implemented using Linked lists, and Linked Lists are not suitable for such use (ie. random access and efficient indexing).
You would have to store all the elements until "a" (inclusive) somewhere, then remove them from the list using LTRIM and then push them again in the order you want (ie. after RPOPing the last element and LPUSHing it). You could do this using an embedded Lua script since Redis supports this out of the box.
However, if you want each word to appear only once in your list, you could do this efficiently using a Sorted Set. You would have to just update the score of the specific element to something greater than all the others (ZADD). Then you'd do a ZRANGEBYSCORE to retrieve the re-ordered set.
However, using a sorted set has its trade-offs, mostly that insertion/deletion of elements is slower (ie. happens in logarithmic time) than pushing/poping values from a list (ie. happens in constant time). It all depends in your problem, you should weigh the different approaches (Redis documentation provides the time complexity of each operation) and pick the one that fits your problem.
I wrote a lua script that will move an item forwards or backwards in a list:
https://github.com/stereosteve/redis-moveby
As the readme indicates, a sorted set may be a better option, and I have not used this in production, so use with care.