Redis Data Types Overview0:00
Next, let's switch over to sorted sets. So as you'll find, there are a number of different data types with Redis. And this can get a little overwhelming if you look through these commands. I think there's like 150 of them. Lots of stuff here. However, you might feel better if you realize that many of these commands are exclusive to specific data types. So for example, if we were to take a look at lists, we're going to see a common convention here. The command name begins with the letter L. L for list. And a list, just think of that as the most basic possible array. In PHP, you create an array, you throw a bunch of values in there. It's a list of items. So when we want to work with lists, usually we'll reference a command that begins with L. So for example, if we were to say, how about this one, LPush, that adds a new item to our array or to our list. And specifically, it's going to add that to the left side. There's also a RPush. And that will
if we were to say, how about this one, lpush, that adds a new item to our array or to our list. And specifically, it's going to add that to the left side. There's also an rpush. And that will add it to the end of the array, more traditionally, like you might have with php. But anyways, that's a list. We're going to talk about all these quite a bit more. But then you have things like hashes, think of that as like an object or even like an associative array in php, where you can assign multiple key value pairs, like a hash. Next, we have sets. Now, a set is like a list, but it has a few little bonuses, such as the fact that it's unique. So if I were to add to a set, 1, 2, 3, 4, 1, 2, 3, 4, well, ultimately, it's just going to contain 1, 2, 3, 4. So all of the items in a set will be unique. However, they're not in any particular order. So that brings us to what we're covering in this episode, which is a sorted set. So it's very similar to a set. But the
Sorted Sets in CLI2:24
OK, so before we dig in, once again, to reiterate, a list is a simple array, often beginning with the letter L for list. A set is like an array, but all of the items are unique, and they will often begin with the letter S, S for set. Next, a hash is kind of like an object or an associative array. It will often begin with the letter H. And finally, we come down to sorted set, and all of those will begin with the letter Z. OK, so let's try this out first in the command line, and then we'll switch over. So here's a quick command you can run, flush all. So when you're just practicing, obviously, you can fill up your database with lots of gibberish. From time to time, especially when you're practicing, just flush it out, and that will clear everything. OK, so why don't we use this command right here, zadd. So this will add an item to a sorted set, but you'll see if we come down to the examples, we have to include
and that will clear everything. OK, so why don't we use this command right here, zadd. So this will add an item to a sorted set, but you'll see if we come down to the examples, we have to include a score. And once again, this can be anything. It can be a timestamp. It can be an age. It can be a download count. Any of those will be fine. So why don't we try it out, zadd. And I already know I'm going to show you this concept of trending articles. So the articles that have been most viewed on our site, we're going to store in a sorted set. Now, why wouldn't we use a list for this? Well, a list would be fine, but there's not going to be any sorting at all. So a list might be good for most recent blog posts or most recent forum replies. However, in our case, we want trending. We want most popular. So if you can associate the term trending or popular or leaderboard, if you ever reference those words, you probably want a sorted set. OK, so we call
trending. We want most popular. So if you can associate the term trending or popular or leaderboard, if you ever reference those words, you probably want a sorted set. OK, so we call our command. We reference our key. This does not exist yet, but that's OK. It'll be created on the fly. And then if we switch back, we can see we can add a couple options here. We won't worry about that. But then we give a score and then the member, which is like the item of the array, so to speak. So let's just default to 1 and then we'll use like a slug, like learn PHP. OK, so now if we want to fetch all of the items within the sorted set, I can use ZRange. And by the way, if I was working with a list and not a sorted set, I could use LRange. So you'll see there's a lot of commands. However, there's a lot of overlap here. Anyways, we're going to use ZRange, but maybe you don't remember what the order of the items are. You can always say help and then
a lot of commands. However, there's a lot of overlap here. Anyways, we're going to use ZRange, but maybe you don't remember what the order of the items are. You can always say help and then the command name. So in this case, we give it the key. Once again, trendingArticles, where we want to start with our range and where we want to end. So that means I could say ZRange on trendingArticles start. It's zero based. So start with the very first one and then we're going to use -1 to represent the very last item. And in this case, we just have one. Let's add another one to it. Let's do learn. These are like blog posts or something. learn HTML. And then learn CSS. And let's get our range again. OK, now we have three items. And we can also use this command called ZCard trendingArticles. And this will return the total number of items. But so far, this just feels like a list to us, right? What makes this sorted? Where
Scoring and Ranking5:29
And we can also use this command called ZCARD trending_articles. And this will return the total number of items. But so far, this just feels like a list to us, right? What makes this sorted? Where do the votes come into play? Well, we'll take a look at this. If we let's do this, help ZRANGE one more time. And there is a WITHSCORES option you can add. So let's run that again. But I will add that on. OK, so now you get each of the item, but below it is the associated score. So learn:css is one, html is one, and php is one. Why don't we increment one of these and we can use ZINCRBY once again, you already learned about INCRBY, right? So we're just adding Z to mean we're adding it to a sorted set. OK, so we're going to increment. Let's review our help. OK, so we give it the key, the amount to increment and then the item of the array or the member of the array. See INCRBY trending_articles, we will increment by one. And specifically, I think it
it the key, the amount to increment and then the item of the array or the member of the array. See increment by trending articles, we will increment by one. And specifically, I think it was called learn HTML. Yeah. And now that returns to. So if we get our range again, now you can see that 2 is at the bottom. But why don't we increment CSS? Because everyone wants to learn that, right? So let's increment learn CSS. And we're going to increment that by like 10. And that will represent maybe 10 visits to our site. OK, so if we run it again, now, you'll see that CSS is at the bottom. So our sorting is from least votes or least score to most score. But what if you want it reverse like you often would? So if you want to show trending articles, well, you want the most trending, the most popular article on your site at the very top. So let's go back to Chrome and you'll see that often. Let's go back to commands and to our sorted sets. You'll
you want the most trending, the most popular article on your site at the very top. So let's go back to Chrome and you'll see that often. Let's go back to commands and to our sorted sets. You'll see that often. Yeah, some of these command names are kind of crazy. But once you figure out what they stand for, they are a little easier to take in. So like I said, we have ZRange, right? Return a range of members. However, you'll see ZRev, ZRevRange by Lex and ZRevRange by score. And then just simple ZRevRange. Rev, of course, stands for reverse. So that means you have ZRange, but ZRevRange is just the exact same thing, but sorted in the opposite order. So if we were to try this again, ZRevRange. Now learnCSS will be on the top. All right. So now let's imagine we do some promotion and we get tons of clicks for PHP. We're going to come back, increment learnPHP by, let's say, 400 people visited the site and got featured on Reddit or something.
Trending Articles Example8:02
promotion and we get tons of clicks for php. We're going to come back, increment, learn PHP by, let's say, 400 people visited the site and got featured on Reddit or something. Okay. Well now we've incremented our trending articles. So if we once again say Zrange trending articles, give me all of them. PHP is at the bottom, which is the top. Or once again, we do Zrevrange to reverse the order. And now learn PHP is our most popular article. And now learn PHP is the most popular article or popular slug. Kind of cool, right? You'll think of countless uses for this. So to show you a very quick example, I've quickly set up a set of articles. So if I were to say php artisan tinker, you'll see that we have 10 articles in the database and they're super, super simple. They just have a title really. So let's do this. We'll say when we receive a request to articles/article, we will find the article. I'm just
database and they're super, super simple. They just have a title really. So let's do this. We'll say when we receive a request to /articles/{article}, we will find the article. I'm just going to use implicit route model binding here. And for example, if we were to return that and we'll go to learn.redis.dev/articles/1. And there we go. There's article one, two, three, we fetch those. But now like we've learned about in the last episode, we want to record this visit so we can increase the rank of this particular article. Okay. So come back and we'll say redis. And what was the method? Z::incrementBy. Now you'll remember that originally we used Z::add. However, just like with incrementBy, you could do Z::incrementBy and it will create the key if it doesn't exist. So we give our key name, the votes or the score we're going to give it is just one, of course. And then the member will be. And like I said, this can be a value if you want.
if it doesn't exist. So we give our key name, the votes or the score we're going to give it is just one, of course. And then the member will be. And like I said, this can be a value if you want. So it could be the ID of the article. So if all you want to do is just store the IDs of the most popular articles, you could do this. And then what you could do is say articles/trending. Well, in that case, you fetch the items. So Z sorted set, reverse range, trending articles, and we could get all of them. Or maybe we just want the top three. Well, we could do this. Once again, zero based. So zero, one, two equals the top three. Now, if we were to return that, you would have an array of the top three trending articles on your website. And all it required was two lines of code to accomplish that. So hopefully this gets you a little excited. And even better, yes, you could store like a count column in your database table. And for small sites,
two lines of code to accomplish that. So hopefully this gets you a little excited. And even better, yes, you could store like a count column in your database table. And for small sites, it really doesn't matter. That's totally fine. But for more traffic, yeah, you don't need to do that. This is going to be a blazing fast alternative. Okay, so let's go over this. The User visits an Article. As part of that request, we increment this particular key by one. So the Article with an ID of one was incremented by one. And if we were to give that a refresh, then the Article with an ID of one was incremented again. So now its score is two. But if the User visits the Article with an ID of five, well, now it has a score of one. And you can see how that works. Finally, when we go to /article/trending, we're going to fetch a range of all of the members or the items in that sorted set,
And you can see how that works. Finally, when we go to article/trending, we're going to fetch a range of all of the members or the items in that sorted set, specifically three, and in reverse order so that we can see the most popular or the highest scoring ones on top. All right, let's try this out. So I'm going to do redis-cli, flush everything out so we can start from scratch. So if I were to do keys *, yeah, there's nothing in there. Okay, so we're going to do article 1. And now if we run it, there we go. See rev range trending articles, z -1, I'm sorry, 0 -1. And here you get the number one. Remember, that would be the identifier. It's not as readable for us like the slug was, but it's the same thing. So let's do the article with an ID of 5. Run it. Okay. Let's go back to article 1. And that's getting a lot of traffic.
the slug was, but it's the same thing. So let's do the Article with an ID of five. Run it. Okay. Let's go back to Article one. And that's getting a lot of traffic. Run it again. Now it's the most popular. But now you have three. Okay. And then finally, you add a new one. And that's super, super popular. It gets featured on Reddit, and you get lots of clicks. Okay, so now the one with six is the most popular Article on your site. So now you have a dynamic array of article IDs that you can then use for your trending page. Right here, fetch the top three, and return them. So if we try this out, trending, and not found exception out whoops, of course, because we have a wildcard here. So we run it again. And now we see our array of the most trending articles, which you could then do like app(Article::class) where an ID is trending to fetch all of those three articles. Or if you
Storing JSON and Hydrating13:02
So we run it again. And now we see our array of the most trending articles, which you could then do like app('article'), where an ID is trending to to fetch all of those three articles. Or if you don't want to store the ID, what if we did this? Let's do it again. Let's flush all. What if we were to just pass the article? So what you may know is that with Eloquent, if you cast it to a string, that's going to convert it to JSON, which essentially means it's going to do toJson, called toJson. So if we leave that off, it's going to do the exact same thing. Okay, well, let's try that out now. So article/1, excuse me. All right. And if we fetch, yeah, now you can see that we've taken all of the attributes for the model, we've converted them to JSON, and then we threw that in the Redis. All right, let's try another one, two, three, but the article with an ID of five is super popular, so it should be on top.
we've converted them to JSON, and then we threw that in the Redis. All right, let's try another one, two, three, but the article with an ID of five is super popular, so it should be on top. All right, so we run it now. And sure enough, the ID of five is number one. So now what you could do in this case, is yes, we fetch all the trending articles. However, we have to decode them, right, and then also rehydrate them. So maybe you could do something like this, hydrate. If you're not familiar with hydrate, it accepts an array of records, essentially, and it filters through them and creates for each one, a new instance of the model, while passing through the attributes. So I could say, let's hydrate this, but make sure that we JSON decode all of the items within here. So we will map over all of the trending items, and for each one, we're just going to decode it. Or you could even create like a global
JSON decode all of the items within here. So we will map over all of the trending items, and for each one, we're just going to decode it. Or you could even create like a global query scope, so that you could say, add Article hydrate from JSON string or hydrate from JSON, whatever you want there, and then it would do that for you. Anyways, now you'll have your trending array of Article models. And if we were to just dd those, let's come back to Chrome, go to trending. And there you go, you have a traditional collection of articles, where this one is the most popular. Let's go to articles 10. And that's going to be even more popular than all of them. All right, back to trending. Now it will be the very top item. And because we only fetch the top three, any of the others will just be ignored in this case. Now, one question you might have before we finish up, though, is that, well,
Managing Sorted Set Size15:24
very top item. And because we only fetch the top three, any of the others will just be ignored in this case. Now, one question you might have before we finish up, though, is that, well, for every single article, we're going to push to this sorted set. So it could grow and grow. And I think the reality is, it doesn't matter too much. Because Redis is so fast. I've heard situations where people have millions of records in a sorted set, and it's still very, very snappy and doesn't use up that much memory. However, even if it would only make you feel better, maybe you could set up a cron job to occasionally clear these out. So for example, you wouldn't want to do this here. But just to show you the code, you could use the command ZREM RANGE BY RANK. Yeah, Redis gets kind of crazy with this. But once again, you break it down, and it's a little easier to understand. Z for sorted set, REM will
Now, you might be wondering, though, well, why not just keep this in here? And that way, you always limit it to the top three. But if you think about it, you actually wouldn't want to do that. And that's because new items would never even have the opportunity to increase their score, because they would immediately be removed from the bottom. Let me give you an example. Back to Chrome, let's do article/. Well, before we do that, let's get our range. We have five here. Okay. But we're going to go to the article with an ID of 7. So now we hit our updated code, where we are removing all but the very top three items with the highest score at the end of our array. So if we do it now, you'll see that we have limited the results to three. But notice we have IDs 10, 5, 1. So we're trying to get this one to grow. And even if it gets 100 different views, the way we've set up our code, it never even
limited the results to three. But notice we have IDs 10, 5, 1. So we're trying to get this one to grow. And even if it gets 100 different views, the way we've set up our code, it never even has the opportunity to increase its rank, because it's immediately removed. So yeah, what you might do is you could set up like a cron job. Even with Laravel, you could use your ConsoleKernel class, and then come down here and actually schedule a Redis command to be run once a week or once a month, where maybe you only want to keep the top 100 items. So you run this once a month just to get rid of any of the old stuff. Or, yeah, if you just have a blog, and you're never going to have more than 200 articles, best case scenario, you wouldn't need to worry about this at all. Just leave them in there. Okay, so think about how cool this actually is. We've specified that when you visit an article, we are going to push to a sorted set that will
