{"id":390096,"date":"2024-06-29T09:01:45","date_gmt":"2024-06-29T09:01:45","guid":{"rendered":"http:\/\/savepearlharbor.com\/?p=390096"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-29T21:00:00","slug":"","status":"publish","type":"post","link":"https:\/\/savepearlharbor.com\/?p=390096","title":{"rendered":"<span>How to create LinkedIn-like reactions with Serverless Redis<\/span>"},"content":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>Originally posted on\u00a0<a href=\"https:\/\/dev.to\/sandorturanszky\/how-to-create-linkedin-like-reactions-with-serverless-redis-4cad\" rel=\"noopener noreferrer nofollow\">DEV.to<\/a><\/p>\n<p>As a side hustle, I teach tech recruiters web and software development technologies using plain English. It helps them with understanding job specs and resumes and it makes all of us, tech people, happier.<\/p>\n<p>I run a weekly newsletter and often get feedback from recruiters via email or LinkedIn DMs.<\/p>\n<p>I thought that I could try to collect feedback using the \u201cReactions\u201d feature just like LinkedIn or Facebook does. It\u2019s not as informative as personalised messages but is a simple feature that may incentivize more people to provide some general feedback.<\/p>\n<p>Either way, it\u2019s worth trying and as a software developer, I can\u2019t wait to implement it.<\/p>\n<p>This tutorial is about implementing a feature that will be used in real life on my project.<\/p>\n<h4>Planning<\/h4>\n<p>As with any feature or project, we start with the planning phase.<\/p>\n<p>I am going to stick with LinkedIn-like reactions because they are more appropriate for the type of content I post.<\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/8ed\/776\/127\/8ed776127deab9153adf7eaac1a9e511.png\" width=\"880\" height=\"230\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/8ed\/776\/127\/8ed776127deab9153adf7eaac1a9e511.png\"\/><figcaption><\/figcaption><\/figure>\n<p>I will use the Like, Insightful and Curious reactions and will substitute them with \u200b, \u200b and \u200b emojis respectively.<\/p>\n<p>My static website is built with Gatsby. I do not use a database but I need one to store reactions. I need to decide what database to use.<\/p>\n<p>I deploy with Netlify and I use functions for backend related functionality. That means that I go serverless. Ideally, I need a serverless database too to not have to deal with deploying my own DB or overpaying for PaaS with fixed plans.<\/p>\n<p>As of writing this article, I am using Netlify&#8217;s free tier and can easily go for more features with a paid plan at a very good price. Using a reasonably priced database would be a perfect complement to my current tech stack.<\/p>\n<p>These are the tasks:<\/p>\n<ol>\n<li>\n<p><strong>Research database options.<\/strong><br \/>I need to find out what serverless databases exist and choose one.<\/p>\n<\/li>\n<li>\n<p><strong>Create a Serverless Backend with functions for:<\/strong><br \/>&#8212; storing reactions and incrementing\/decrementing the count<br \/>&#8212; fetching reactions by a post id<\/p>\n<\/li>\n<li>\n<p><strong>Create the &#171;reactions&#187; component.<\/strong><br \/>Gatsby is based on React and I will build a simple \u201creactions\u201d component.<\/p>\n<\/li>\n<li>\n<p><strong>Put it all together to make my static website a little bit dynamic.<\/strong><br \/>Static websites can have dynamic features and it\u2019s what makes them, static site generators so incredibly awesome.<\/p>\n<\/li>\n<\/ol>\n<p>In this tutorial, I will focus on the first two tasks. The \u201creactions&#187; component implementation you can check in the\u00a0<a href=\"https:\/\/github.com\/sandorTuranszky\/gatsby-starter-blog-with-LinkedIn-like-reactions\/tree\/main\/src\/components\" rel=\"noopener noreferrer nofollow\"><u>source code<\/u><\/a><\/p>\n<h4>Research<\/h4>\n<p>This second phase in Software Development Life Cycle (SDLC) is named Prototyping but I call it Research in this tutorial because I will skip the proof of concept (POC) part.<\/p>\n<p>Research is always fun because it provides a great opportunity to learn about new technologies. While this process is interesting, it can also take a lot of time if we do not make our research more specific.<\/p>\n<p>SQL and NoSQL are the most common database types. The choice isn\u2019t difficult if we know what data will be stored. Let\u2019s quickly take a look at what data structure we will have.<\/p>\n<p>Every\u00a0<strong>post has a set of reactions<\/strong>\u00a0and we need to\u00a0<strong>count<\/strong>\u00a0those\u00a0<strong>reactions<\/strong>.<\/p>\n<p>Since I simply want to get an idea about how people react to my posts, I will not require them to log in or limit the types of reactions.<\/p>\n<p>Based on the above, our data structure could look as follows for a post with 3 likes, 12 insightful and 7 curious reactions:\u00a0<code>{ \"like\":3, \"insightful\":12, \"curious\":7 }<\/code><\/p>\n<p>A NoSQL database looks like a good choice for storing and manipulating a data structure like the above.<\/p>\n<p>I immediately thought of MongoDB and Redis. However, based on how we will manipulate data, namely persist it once and then increment or decrement certain values, I decide in favor of Redis.<\/p>\n<p>The reason being is that Redis has built-in and performance-optimized commands to support what we need.<\/p>\n<p>Besides that, I found a serverless Redis database\u00a0<a href=\"https:\/\/upstash.com\/?utm_source=sndr_1\" rel=\"noopener noreferrer nofollow\"><u>Upstash<\/u><\/a>\u00a0which looks simple and has reasonable pricing including a free plan. I like starting free and paying as I scale.<\/p>\n<p>Note that we are using Redis as a\u00a0<strong>primary database<\/strong>. Redis can be configured to write data to disk which provides a degree of\u00a0<a href=\"https:\/\/redis.io\/topics\/persistence\" rel=\"noopener noreferrer nofollow\"><u>data safety<\/u><\/a>\u00a0comparable to what PostgreSQL offers.<\/p>\n<p>Redis solves a much wider range of problems than just in-memory caching and can be used either as a primary database or as an additional database for solving problems that other databases struggle with.<\/p>\n<p>I like that Upstash\u00a0<a href=\"https:\/\/docs.upstash.com\/overall\/durability?utm_source=sndr_1\" rel=\"noopener noreferrer nofollow\"><u>enables persistence<\/u><\/a>\u00a0by default keeping data both in memory and disk. This removes the headache of configuring things which would be an overhead for a task like this one. This is why I always use serverless and PaaS whenever possible.<\/p>\n<p>To sum up this part, let me share with you an interesting\u00a0<a href=\"https:\/\/redislabs.com\/ebook\/redis-in-action\/\" rel=\"noopener noreferrer nofollow\"><u>free e-book<\/u><\/a>\u00a0called \u201cRedis in Action\u201d packed with valuable information and use-cases for Redis.<\/p>\n<h4>Serverless Backend<\/h4>\n<p>I will use Netlify\u2019s serverless functions with Node instead of creating my own backend. You are free to use any backend architecture.<\/p>\n<p>The easiest way to connect Redis with Upstash is to use the\u00a0<a href=\"https:\/\/github.com\/NodeRedis\/node-redis\" rel=\"noopener noreferrer nofollow\"><u>redis-client<\/u><\/a>\u00a0as described\u00a0<a href=\"https:\/\/docs.upstash.com\/howto\/connectwithtls?utm_source=sndr_1\" rel=\"noopener noreferrer nofollow\"><u>here<\/u><\/a>.<\/p>\n<p>First things first, we need to create a Serverless Redis database following this\u00a0<a href=\"https:\/\/docs.upstash.com\/?utm_source=sndr_1\" rel=\"noopener noreferrer nofollow\"><u>Getting Started guide<\/u><\/a>.<\/p>\n<p>Please, note that I leave out the\u00a0<a href=\"https:\/\/docs.upstash.com\/overall\/consistency?utm_source=sndr_1\" rel=\"noopener noreferrer nofollow\"><u>Strong Consistency Mode<\/u><\/a>, because Eventual Consistency is suitable for my task.<\/p>\n<p>This is the schema for naming the keys:\u00a0<strong>post:{id}:{reaction}<\/strong><\/p>\n<ol>\n<li>\n<p><strong>post:{id}:like<\/strong>\u00a0->\u00a0<code>post:856f9d0a:like<\/code><\/p>\n<\/li>\n<li>\n<p><strong>post:{id}:insightful<\/strong>\u00a0->\u00a0<code>post:856f9d0a:insightful<\/code><\/p>\n<\/li>\n<li>\n<p><strong>post:{id}:curious<\/strong>\u00a0->\u00a0<code>post:856f9d0a:curious<\/code><\/p>\n<\/li>\n<\/ol>\n<p>We could go with the most basic kind of Redis value known as\u00a0<a href=\"https:\/\/redis.io\/topics\/data-types#strings\" rel=\"noopener noreferrer nofollow\"><u>Strings<\/u><\/a>. But we\u2019ll go with\u00a0<a href=\"https:\/\/redis.io\/topics\/data-types#hashes\" rel=\"noopener noreferrer nofollow\"><u>hashes<\/u><\/a>\u00a0because we want to store objects as value and it is advisable to\u00a0<a href=\"https:\/\/redis.io\/topics\/memory-optimization\" rel=\"noopener noreferrer nofollow\"><u>use hashes when possible<\/u><\/a>.<\/p>\n<p>This is how we do it for a given post ID:<\/p>\n<ul>\n<li>\n<p>To increment a reaction by 1, for example, \u201cLike\u201d, we will use the\u00a0<a href=\"https:\/\/redis.io\/commands\/hincrby\" rel=\"noopener noreferrer nofollow\"><u>HINCRBY<\/u><\/a>\u00a0command. If the key does not exist, it will create the key and set its value to 0 before incrementing. If the key does exist, it will simply increment by the value we provide. It allows us to reuse this function both for creating and updating reactions.<\/p>\n<\/li>\n<\/ul>\n<p><code>HINCRBY post:856f9d0a:reactions like 1<\/code><\/p>\n<p>Here is the\u00a0<a href=\"https:\/\/github.com\/sandorTuranszky\/gatsby-starter-blog-with-LinkedIn-like-reactions\/blob\/main\/lambda\/react.js\" rel=\"noopener noreferrer nofollow\"><u>implementation<\/u><\/a><\/p>\n<p>If we had to decrement reactions for cases when a reaction is removed or changed, we would simply pass the value to be incremented by a negative number: -1<\/p>\n<ul>\n<li>\n<p>To read reactions for a post ID we\u2019ll use the\u00a0<a href=\"https:\/\/redis.io\/commands\/hgetall\" rel=\"noopener noreferrer nofollow\"><u>HGETALL<\/u><\/a>\u00a0command which returns key-value pairs:<\/p>\n<\/li>\n<\/ul>\n<p><code>HGETALL post:856f9d0a:reactions<\/code>\u00a0->\u00a0<code>\/\/ will return {\"like\":\"3\",\"insightful\":\"1\",\"curious\":\"2\"}<\/code><\/p>\n<p>Here is the\u00a0<a href=\"https:\/\/github.com\/sandorTuranszky\/gatsby-starter-blog-with-LinkedIn-like-reactions\/blob\/main\/lambda\/reactions.js\" rel=\"noopener noreferrer nofollow\"><u>implementation<\/u><\/a><\/p>\n<p>With this approach, knowing the post ID, we can efficiently set, update and retrieve reactions for a post with a ridiculously small amount of code.<\/p>\n<p>Post IDs are not short but we will use them for naming keys because they will not cause any noticeable memory usage increase in our case.<\/p>\n<p>But you should always keep in mind that along with having a readable key naming schema, you need to control the length of keys. Long keys can use more memory and even cause performance implications as described in the\u00a0<a href=\"https:\/\/redis.io\/topics\/data-types-intro#redis-keys\" rel=\"noopener noreferrer nofollow\"><u>Redis keys<\/u><\/a>\u00a0section.<\/p>\n<h4>Off-topic<\/h4>\n<p>Even though this is not directly related to this tutorial, I know that later I will want to show the most popular posts based on reactions.<\/p>\n<p>To get posts with the most Likes, Insightful and Curious reactions, we need to track them using a\u00a0<a href=\"https:\/\/redis.io\/topics\/data-types#sorted-sets\" rel=\"noopener noreferrer nofollow\"><u>sorted set<\/u><\/a>.<\/p>\n<p>For instance, this is how we store a post that received a Like reaction:<br \/><a href=\"https:\/\/redis.io\/commands\/zincrby\" rel=\"noopener noreferrer nofollow\"><u>ZINCRBY<\/u><\/a>\u00a0<code>reaction:like 1 post:856f9d0a<\/code><\/p>\n<p>And this is how we get the most liked 5 posts:<br \/><a href=\"https:\/\/redis.io\/commands\/zrevrangebyscore\" rel=\"noopener noreferrer nofollow\"><u>ZREVRANGEBYSCORE<\/u><\/a>\u00a0<code>reaction:like +INF -INF withscores LIMIT 0 5<\/code><\/p>\n<p>I will provide more details and a working implementation in one of my next posts.<\/p>\n<p>It\u2019s always a good idea to design a system taking into account all known future requirements and choose technologies that will support them in the future.<\/p>\n<hr\/>\n<p>Here is a working implementation on my\u00a0<a href=\"https:\/\/techforitrecruiters.com\/blog\" rel=\"noopener noreferrer nofollow\"><u>website<\/u><\/a>. Pick any\u00a0<a href=\"https:\/\/techforitrecruiters.com\/blog\/2021-05-02-what-is-a-content-management-system\/\" rel=\"noopener noreferrer nofollow\"><u>post<\/u><\/a>\u00a0and you will find reactions at the bottom. The source code you can find\u00a0<a href=\"https:\/\/github.com\/sandorTuranszky\/gatsby-starter-blog-with-LinkedIn-like-reactions\" rel=\"noopener noreferrer nofollow\"><u>here<\/u><\/a><\/p>\n<figure class=\"full-width\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/habrastorage.org\/r\/w1560\/getpro\/habr\/upload_files\/db1\/ccf\/410\/db1ccf410d998f1c429b30a3b6870fea.png\" width=\"880\" height=\"300\" data-src=\"https:\/\/habrastorage.org\/getpro\/habr\/upload_files\/db1\/ccf\/410\/db1ccf410d998f1c429b30a3b6870fea.png\"\/><figcaption><\/figcaption><\/figure>\n<h4>Conclusion<\/h4>\n<p>If you still perceive Redis as an in-memory cache, get ready because I have more posts coming up that cover powerful features backed by this amazing database.<\/p>\n<p>The next post will be about\u00a0<a href=\"https:\/\/dev.to\/sandorturanszky\/you-don-t-know-redis-3onh\" rel=\"noopener noreferrer nofollow\"><strong><u>how I built a Q&amp;A board<\/u><\/strong><\/a>\u00a0for asking and upvoting the most interesting questions using Redis.<\/p>\n<p>Follow for more!<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/568872\/\"> https:\/\/habr.com\/ru\/articles\/568872\/<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<div><!--[--><!--]--><\/div>\n<div id=\"post-content-body\">\n<div>\n<div class=\"article-formatted-body article-formatted-body article-formatted-body_version-2\">\n<div xmlns=\"http:\/\/www.w3.org\/1999\/xhtml\">\n<p>Originally posted on\u00a0<a href=\"https:\/\/dev.to\/sandorturanszky\/how-to-create-linkedin-like-reactions-with-serverless-redis-4cad\" rel=\"noopener noreferrer nofollow\">DEV.to<\/a><\/p>\n<p>As a side hustle, I teach tech recruiters web and software development technologies using plain English. It helps them with understanding job specs and resumes and it makes all of us, tech people, happier.<\/p>\n<p>I run a weekly newsletter and often get feedback from recruiters via email or LinkedIn DMs.<\/p>\n<p>I thought that I could try to collect feedback using the \u201cReactions\u201d feature just like LinkedIn or Facebook does. It\u2019s not as informative as personalised messages but is a simple feature that may incentivize more people to provide some general feedback.<\/p>\n<p>Either way, it\u2019s worth trying and as a software developer, I can\u2019t wait to implement it.<\/p>\n<p>This tutorial is about implementing a feature that will be used in real life on my project.<\/p>\n<h4>Planning<\/h4>\n<p>As with any feature or project, we start with the planning phase.<\/p>\n<p>I am going to stick with LinkedIn-like reactions because they are more appropriate for the type of content I post.<\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<p>I will use the Like, Insightful and Curious reactions and will substitute them with \u200b, \u200b and \u200b emojis respectively.<\/p>\n<p>My static website is built with Gatsby. I do not use a database but I need one to store reactions. I need to decide what database to use.<\/p>\n<p>I deploy with Netlify and I use functions for backend related functionality. That means that I go serverless. Ideally, I need a serverless database too to not have to deal with deploying my own DB or overpaying for PaaS with fixed plans.<\/p>\n<p>As of writing this article, I am using Netlify&#8217;s free tier and can easily go for more features with a paid plan at a very good price. Using a reasonably priced database would be a perfect complement to my current tech stack.<\/p>\n<p>These are the tasks:<\/p>\n<ol>\n<li>\n<p><strong>Research database options.<\/strong><br \/>I need to find out what serverless databases exist and choose one.<\/p>\n<\/li>\n<li>\n<p><strong>Create a Serverless Backend with functions for:<\/strong><br \/>&#8212; storing reactions and incrementing\/decrementing the count<br \/>&#8212; fetching reactions by a post id<\/p>\n<\/li>\n<li>\n<p><strong>Create the &#171;reactions&#187; component.<\/strong><br \/>Gatsby is based on React and I will build a simple \u201creactions\u201d component.<\/p>\n<\/li>\n<li>\n<p><strong>Put it all together to make my static website a little bit dynamic.<\/strong><br \/>Static websites can have dynamic features and it\u2019s what makes them, static site generators so incredibly awesome.<\/p>\n<\/li>\n<\/ol>\n<p>In this tutorial, I will focus on the first two tasks. The \u201creactions&#187; component implementation you can check in the\u00a0<a href=\"https:\/\/github.com\/sandorTuranszky\/gatsby-starter-blog-with-LinkedIn-like-reactions\/tree\/main\/src\/components\" rel=\"noopener noreferrer nofollow\"><u>source code<\/u><\/a><\/p>\n<h4>Research<\/h4>\n<p>This second phase in Software Development Life Cycle (SDLC) is named Prototyping but I call it Research in this tutorial because I will skip the proof of concept (POC) part.<\/p>\n<p>Research is always fun because it provides a great opportunity to learn about new technologies. While this process is interesting, it can also take a lot of time if we do not make our research more specific.<\/p>\n<p>SQL and NoSQL are the most common database types. The choice isn\u2019t difficult if we know what data will be stored. Let\u2019s quickly take a look at what data structure we will have.<\/p>\n<p>Every\u00a0<strong>post has a set of reactions<\/strong>\u00a0and we need to\u00a0<strong>count<\/strong>\u00a0those\u00a0<strong>reactions<\/strong>.<\/p>\n<p>Since I simply want to get an idea about how people react to my posts, I will not require them to log in or limit the types of reactions.<\/p>\n<p>Based on the above, our data structure could look as follows for a post with 3 likes, 12 insightful and 7 curious reactions:\u00a0<code>{ \"like\":3, \"insightful\":12, \"curious\":7 }<\/code><\/p>\n<p>A NoSQL database looks like a good choice for storing and manipulating a data structure like the above.<\/p>\n<p>I immediately thought of MongoDB and Redis. However, based on how we will manipulate data, namely persist it once and then increment or decrement certain values, I decide in favor of Redis.<\/p>\n<p>The reason being is that Redis has built-in and performance-optimized commands to support what we need.<\/p>\n<p>Besides that, I found a serverless Redis database\u00a0<a href=\"https:\/\/upstash.com\/?utm_source=sndr_1\" rel=\"noopener noreferrer nofollow\"><u>Upstash<\/u><\/a>\u00a0which looks simple and has reasonable pricing including a free plan. I like starting free and paying as I scale.<\/p>\n<p>Note that we are using Redis as a\u00a0<strong>primary database<\/strong>. Redis can be configured to write data to disk which provides a degree of\u00a0<a href=\"https:\/\/redis.io\/topics\/persistence\" rel=\"noopener noreferrer nofollow\"><u>data safety<\/u><\/a>\u00a0comparable to what PostgreSQL offers.<\/p>\n<p>Redis solves a much wider range of problems than just in-memory caching and can be used either as a primary database or as an additional database for solving problems that other databases struggle with.<\/p>\n<p>I like that Upstash\u00a0<a href=\"https:\/\/docs.upstash.com\/overall\/durability?utm_source=sndr_1\" rel=\"noopener noreferrer nofollow\"><u>enables persistence<\/u><\/a>\u00a0by default keeping data both in memory and disk. This removes the headache of configuring things which would be an overhead for a task like this one. This is why I always use serverless and PaaS whenever possible.<\/p>\n<p>To sum up this part, let me share with you an interesting\u00a0<a href=\"https:\/\/redislabs.com\/ebook\/redis-in-action\/\" rel=\"noopener noreferrer nofollow\"><u>free e-book<\/u><\/a>\u00a0called \u201cRedis in Action\u201d packed with valuable information and use-cases for Redis.<\/p>\n<h4>Serverless Backend<\/h4>\n<p>I will use Netlify\u2019s serverless functions with Node instead of creating my own backend. You are free to use any backend architecture.<\/p>\n<p>The easiest way to connect Redis with Upstash is to use the\u00a0<a href=\"https:\/\/github.com\/NodeRedis\/node-redis\" rel=\"noopener noreferrer nofollow\"><u>redis-client<\/u><\/a>\u00a0as described\u00a0<a href=\"https:\/\/docs.upstash.com\/howto\/connectwithtls?utm_source=sndr_1\" rel=\"noopener noreferrer nofollow\"><u>here<\/u><\/a>.<\/p>\n<p>First things first, we need to create a Serverless Redis database following this\u00a0<a href=\"https:\/\/docs.upstash.com\/?utm_source=sndr_1\" rel=\"noopener noreferrer nofollow\"><u>Getting Started guide<\/u><\/a>.<\/p>\n<p>Please, note that I leave out the\u00a0<a href=\"https:\/\/docs.upstash.com\/overall\/consistency?utm_source=sndr_1\" rel=\"noopener noreferrer nofollow\"><u>Strong Consistency Mode<\/u><\/a>, because Eventual Consistency is suitable for my task.<\/p>\n<p>This is the schema for naming the keys:\u00a0<strong>post:{id}:{reaction}<\/strong><\/p>\n<ol>\n<li>\n<p><strong>post:{id}:like<\/strong>\u00a0->\u00a0<code>post:856f9d0a:like<\/code><\/p>\n<\/li>\n<li>\n<p><strong>post:{id}:insightful<\/strong>\u00a0->\u00a0<code>post:856f9d0a:insightful<\/code><\/p>\n<\/li>\n<li>\n<p><strong>post:{id}:curious<\/strong>\u00a0->\u00a0<code>post:856f9d0a:curious<\/code><\/p>\n<\/li>\n<\/ol>\n<p>We could go with the most basic kind of Redis value known as\u00a0<a href=\"https:\/\/redis.io\/topics\/data-types#strings\" rel=\"noopener noreferrer nofollow\"><u>Strings<\/u><\/a>. But we\u2019ll go with\u00a0<a href=\"https:\/\/redis.io\/topics\/data-types#hashes\" rel=\"noopener noreferrer nofollow\"><u>hashes<\/u><\/a>\u00a0because we want to store objects as value and it is advisable to\u00a0<a href=\"https:\/\/redis.io\/topics\/memory-optimization\" rel=\"noopener noreferrer nofollow\"><u>use hashes when possible<\/u><\/a>.<\/p>\n<p>This is how we do it for a given post ID:<\/p>\n<ul>\n<li>\n<p>To increment a reaction by 1, for example, \u201cLike\u201d, we will use the\u00a0<a href=\"https:\/\/redis.io\/commands\/hincrby\" rel=\"noopener noreferrer nofollow\"><u>HINCRBY<\/u><\/a>\u00a0command. If the key does not exist, it will create the key and set its value to 0 before incrementing. If the key does exist, it will simply increment by the value we provide. It allows us to reuse this function both for creating and updating reactions.<\/p>\n<\/li>\n<\/ul>\n<p><code>HINCRBY post:856f9d0a:reactions like 1<\/code><\/p>\n<p>Here is the\u00a0<a href=\"https:\/\/github.com\/sandorTuranszky\/gatsby-starter-blog-with-LinkedIn-like-reactions\/blob\/main\/lambda\/react.js\" rel=\"noopener noreferrer nofollow\"><u>implementation<\/u><\/a><\/p>\n<p>If we had to decrement reactions for cases when a reaction is removed or changed, we would simply pass the value to be incremented by a negative number: -1<\/p>\n<ul>\n<li>\n<p>To read reactions for a post ID we\u2019ll use the\u00a0<a href=\"https:\/\/redis.io\/commands\/hgetall\" rel=\"noopener noreferrer nofollow\"><u>HGETALL<\/u><\/a>\u00a0command which returns key-value pairs:<\/p>\n<\/li>\n<\/ul>\n<p><code>HGETALL post:856f9d0a:reactions<\/code>\u00a0->\u00a0<code>\/\/ will return {\"like\":\"3\",\"insightful\":\"1\",\"curious\":\"2\"}<\/code><\/p>\n<p>Here is the\u00a0<a href=\"https:\/\/github.com\/sandorTuranszky\/gatsby-starter-blog-with-LinkedIn-like-reactions\/blob\/main\/lambda\/reactions.js\" rel=\"noopener noreferrer nofollow\"><u>implementation<\/u><\/a><\/p>\n<p>With this approach, knowing the post ID, we can efficiently set, update and retrieve reactions for a post with a ridiculously small amount of code.<\/p>\n<p>Post IDs are not short but we will use them for naming keys because they will not cause any noticeable memory usage increase in our case.<\/p>\n<p>But you should always keep in mind that along with having a readable key naming schema, you need to control the length of keys. Long keys can use more memory and even cause performance implications as described in the\u00a0<a href=\"https:\/\/redis.io\/topics\/data-types-intro#redis-keys\" rel=\"noopener noreferrer nofollow\"><u>Redis keys<\/u><\/a>\u00a0section.<\/p>\n<h4>Off-topic<\/h4>\n<p>Even though this is not directly related to this tutorial, I know that later I will want to show the most popular posts based on reactions.<\/p>\n<p>To get posts with the most Likes, Insightful and Curious reactions, we need to track them using a\u00a0<a href=\"https:\/\/redis.io\/topics\/data-types#sorted-sets\" rel=\"noopener noreferrer nofollow\"><u>sorted set<\/u><\/a>.<\/p>\n<p>For instance, this is how we store a post that received a Like reaction:<br \/><a href=\"https:\/\/redis.io\/commands\/zincrby\" rel=\"noopener noreferrer nofollow\"><u>ZINCRBY<\/u><\/a>\u00a0<code>reaction:like 1 post:856f9d0a<\/code><\/p>\n<p>And this is how we get the most liked 5 posts:<br \/><a href=\"https:\/\/redis.io\/commands\/zrevrangebyscore\" rel=\"noopener noreferrer nofollow\"><u>ZREVRANGEBYSCORE<\/u><\/a>\u00a0<code>reaction:like +INF -INF withscores LIMIT 0 5<\/code><\/p>\n<p>I will provide more details and a working implementation in one of my next posts.<\/p>\n<p>It\u2019s always a good idea to design a system taking into account all known future requirements and choose technologies that will support them in the future.<\/p>\n<hr\/>\n<p>Here is a working implementation on my\u00a0<a href=\"https:\/\/techforitrecruiters.com\/blog\" rel=\"noopener noreferrer nofollow\"><u>website<\/u><\/a>. Pick any\u00a0<a href=\"https:\/\/techforitrecruiters.com\/blog\/2021-05-02-what-is-a-content-management-system\/\" rel=\"noopener noreferrer nofollow\"><u>post<\/u><\/a>\u00a0and you will find reactions at the bottom. The source code you can find\u00a0<a href=\"https:\/\/github.com\/sandorTuranszky\/gatsby-starter-blog-with-LinkedIn-like-reactions\" rel=\"noopener noreferrer nofollow\"><u>here<\/u><\/a><\/p>\n<figure class=\"full-width\"><figcaption><\/figcaption><\/figure>\n<h4>Conclusion<\/h4>\n<p>If you still perceive Redis as an in-memory cache, get ready because I have more posts coming up that cover powerful features backed by this amazing database.<\/p>\n<p>The next post will be about\u00a0<a href=\"https:\/\/dev.to\/sandorturanszky\/you-don-t-know-redis-3onh\" rel=\"noopener noreferrer nofollow\"><strong><u>how I built a Q&amp;A board<\/u><\/strong><\/a>\u00a0for asking and upvoting the most interesting questions using Redis.<\/p>\n<p>Follow for more!<\/p>\n<\/div>\n<\/div>\n<\/div>\n<p><!----><!----><\/div>\n<p><!----><!----><br \/> \u0441\u0441\u044b\u043b\u043a\u0430 \u043d\u0430 \u043e\u0440\u0438\u0433\u0438\u043d\u0430\u043b \u0441\u0442\u0430\u0442\u044c\u0438 <a href=\"https:\/\/habr.com\/ru\/articles\/568872\/\"> https:\/\/habr.com\/ru\/articles\/568872\/<\/a><br \/><\/br><\/br><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[],"tags":[],"class_list":["post-390096","post","type-post","status-publish","format-standard","hentry"],"_links":{"self":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/390096","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=390096"}],"version-history":[{"count":0,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=\/wp\/v2\/posts\/390096\/revisions"}],"wp:attachment":[{"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=390096"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=390096"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/savepearlharbor.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=390096"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}