<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Sam</title>
    <description>The latest articles on DEV Community by Sam (@samthom).</description>
    <link>https://dev.to/samthom</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F868558%2Fa156ed9d-e343-47d2-96fb-21b8d764e8d7.jpeg</url>
      <title>DEV Community: Sam</title>
      <link>https://dev.to/samthom</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/samthom"/>
    <language>en</language>
    <item>
      <title>Why Redis is the new best database ?</title>
      <dc:creator>Sam</dc:creator>
      <pubDate>Fri, 01 Jul 2022 04:41:00 +0000</pubDate>
      <link>https://dev.to/samthom/why-redis-is-the-new-best-database--11ag</link>
      <guid>https://dev.to/samthom/why-redis-is-the-new-best-database--11ag</guid>
      <description>&lt;p&gt;Redis is a simple in-memory key value database mainly used for caching. Redis used to be a simple in-memory database. Now Redis is much more than that. Thanks to Redis modules, apart from the simple data structures such as strings, sets, maps, streams, etc. Redis can now support more complicated operations and data structures like full text search, json, graph and many more. In this article we will look into two components of &lt;a href="https://redis.io/docs/stack/"&gt;Redis Stack&lt;/a&gt;. RediSearch and RedisJSON are two powerful plugins built top on Redis. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9flD-Gx6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/veosvia2mwue8zbgw6jt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9flD-Gx6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/veosvia2mwue8zbgw6jt.png" alt="Redis Modules" width="522" height="96"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you want to use RedisJSON/RediSearch and try along, check out &lt;a href="https://redis.io/docs/stack/get-started/install/docker/"&gt;docker installation&lt;/a&gt; or use &lt;a href="https://redis.com/try-free/"&gt;Redis cloud&lt;/a&gt; free account. Redis cloud gives out $200 credit for free for new accounts.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  RedisJSON
&lt;/h3&gt;

&lt;p&gt;Json is the default language of web. Json is so powerful that we all started using json databases like MongoDB and DynamoDB everywhere in our applications. Now Redis supports json natively, Thanks to RedisJSON. Before RedisJSON the only way to store json inside Redis was by serialising and deserialising into Json and string back and forth. Or we can use Hash to store Json, but Hash only supports single level, to store multi level Json we have to include keys inside Hashes. All of this adds up as overhead to our application.&lt;/p&gt;

&lt;p&gt;But with RedisJSON we have all the control to store and manipulate json natively. RedisJSON provides all the control but with best latency ever possible.&lt;/p&gt;

&lt;p&gt;Once you have a Redis database ready we can start interacting with it. &lt;a href="https://redis.com/redis-enterprise/redis-insight/"&gt;RedisInsight&lt;/a&gt; is the best GUI available to interact with Redis and Redis modules. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--1-16vvJG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9obja3g0gc96uivdryn1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--1-16vvJG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9obja3g0gc96uivdryn1.png" alt="RedisInsight GUI" width="880" height="607"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;RedisInsight GUI - Adding database&lt;/p&gt;

&lt;p&gt;As you can see above after installation use the “ADD REDIS DATABASE” option to add your database and connect to the database. Explaining everything inside RedisInsight is far from the scope of this article. But for now we can use the &lt;strong&gt;Workbench&lt;/strong&gt; and &lt;strong&gt;Command Helper&lt;/strong&gt; to check out the RedisJSON and RediSearch.  &lt;/p&gt;

&lt;p&gt;Let’s look at the Redis module command structure.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;MODULE&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;.&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;OPERATION&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; KEY VALUE/PATH . 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This is the usual structure of a Redis module command. Let’s look at couple of RedisJSON command we are going to use for our very interesting project we are going to do. Let’s store a simple json data to Redis.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SET&lt;/span&gt; &lt;span class="nx"&gt;milkyway&lt;/span&gt; &lt;span class="nx"&gt;$&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;{"age": "13B", "members": ["Mercury", "Venus", "Earth", "Mars", "Jupitor", "Saturn", "Uranus", "Neptune", "Pluto"]}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here &lt;code&gt;milkyway&lt;/code&gt; is the key of the document and &lt;code&gt;$&lt;/code&gt; denotes that it is the root of the document. Run this command inside the workbench and you will get &lt;code&gt;"OK"&lt;/code&gt; as response. Congratulation you have successfully stored a json document inside Redis.&lt;/p&gt;

&lt;p&gt;Now let’s retrieve the Json document stored using the key.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;GET&lt;/span&gt; &lt;span class="nx"&gt;milkyway&lt;/span&gt; &lt;span class="nx"&gt;$&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above command returns then entire document stored. What if you only want to access the array inside the document ? Use the following command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;MGET&lt;/span&gt; &lt;span class="nx"&gt;milkyway&lt;/span&gt; &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;..&lt;/span&gt;&lt;span class="nx"&gt;members&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ix5D34T_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pasp9x1glutb1k67a9ag.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ix5D34T_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pasp9x1glutb1k67a9ag.png" alt="JSON.MGET Output" width="880" height="222"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can see all the outputs of the commands we tried in the above screenshot. Now let’s kick it up a notch by trying more complicated commands.  First of all we have to remove Pluto from list of planets, Thanks to Neil deGrasse Tyson. We can pop our little dwarf planet out by &lt;strong&gt;JSON.ARRPOP&lt;/strong&gt; command. This will remove the last element of the array.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ARRPOP&lt;/span&gt; &lt;span class="nx"&gt;milkyway&lt;/span&gt; &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;..&lt;/span&gt;&lt;span class="nx"&gt;members&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next up we can update the age our galaxy from 13 Billion to 13.6 Billion, Turns out 600 Million years is a very long time. We can use the same command used to create the document to update the document.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SET&lt;/span&gt; &lt;span class="nx"&gt;milkyway&lt;/span&gt; &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;age&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;"13.6B"&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These are the basic commands inside the &lt;strong&gt;JSON&lt;/strong&gt; Module. Check out the entire list of commands &lt;a href="https://redis.io/commands/?group=json"&gt;here&lt;/a&gt;. &lt;/p&gt;

&lt;h3&gt;
  
  
  RediSearch
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;full-text search&lt;/strong&gt; refers to techniques for searching a single computer-stored document or a collection in a full-text database.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;RediSearch is a &lt;strong&gt;full-text search&lt;/strong&gt; and &lt;strong&gt;indexing&lt;/strong&gt; module built on top of Redis. RediSearch provides a simple and fast way to index and query data using any field, and do search and aggregation on an indexed dataset. RediSearch gives super powers to your Redis cache or database. &lt;/p&gt;

&lt;p&gt;We can store data inside hash and create indexes on top of those records. This makes RediSearch very powerful and dynamic. Previously we had to query the entire data and iterate through it to search or modify. Now we can do complex aggregations like grouping and ordering on the data through queries. Since it’s built on top of Redis it is really fast.&lt;/p&gt;

&lt;p&gt;The real magic is when you combine both RedisJSON and RediSearch. Apart from native data structures Redis supports indexing of json data too. This is the super power I mentioned. &lt;/p&gt;

&lt;p&gt;Let’s look into the basic commands of RediSearch inside the demo.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;Apart from coding, I am a passionate reader and I love fantasy. So I combined both of my interest to come up with this demo idea. I want to store basic details of my favourite books inside Redis and build an api endpoint to retrieve information of the book. It’s nothing fancy but enough to dabble with most of the concept of RedisJSON and RediSearch.&lt;/p&gt;

&lt;p&gt;First of all we need to insert json data(book data) into Redis for us to create indexes. I am using a simple javascript to upload all the book details to Redis&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;insertJSON&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;json filepath to be provided.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// read json file&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;buf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;fs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;readFileSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;__dirname&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;argv&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]));&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;JSONStr&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;books&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;JSONStr&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createClient&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="nx"&gt;books&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;book&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;books&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;key&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;book:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nx"&gt;book&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toLowerCase&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nx"&gt;replaceAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;_&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;set&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;.&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;book&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;key&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; - &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;r&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;quit&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Here I am not focusing too much on the key structure since my requirement is less complex and it is not relevant, But good key structure is always important for better access. All code examples and book json file are available in this &lt;a href="https://github.com/samthom/my-library"&gt;repo&lt;/a&gt;. Check out Github repo to follow along.&lt;/p&gt;

&lt;p&gt;Now we have all the json documents stored inside Redis, which can be easily accessed, updated and manipulated natively. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note that inserting json data is not necessary to create new indexes. Indexes can be created independent whether documents exist or not, pre existing json documents will get indexed once the index is created.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Create json indexes
&lt;/h3&gt;

&lt;p&gt;Full-text search module commands follows the same format of json module commands. All commands starts with &lt;strong&gt;FT&lt;/strong&gt; - Full text search.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;FT&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CREATE&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;index_name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;ON&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt; &lt;span class="nx"&gt;PREFIX&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;prefix&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;SCHEMA&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;identifier&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;AS&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;attribute&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;attribute_type&lt;/span&gt;&lt;span class="p"&gt;}...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;index_name&lt;/code&gt; - This is the custom name that can be given to the index created. Usually &lt;code&gt;idx:&amp;lt;key&amp;gt;&lt;/code&gt; is used as a conventions&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ON JSON/HASH&lt;/code&gt; - Index can only be created on these both datatypes. (Default value is HASH)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;PREFIX {count} {prefix}&lt;/code&gt; - Prefix keyword mentions the structure of the keys to be indexed. Count is the number of prefixes to be indexed and we can provide multiple key prefixes. Default value is &lt;code&gt;*&lt;/code&gt;, which is all the keys. Consider our document key structure as &lt;code&gt;book:the_book&lt;/code&gt;, to index all our document use &lt;code&gt;PREFIX 1 book:&lt;/code&gt;. &lt;/li&gt;
&lt;li&gt;
&lt;code&gt;SCHEMA {identifier} AS {attribute} {type}...&lt;/code&gt;  - This is the schema definition part of the command. &lt;em&gt;identifier&lt;/em&gt; is the name of the field to be indexed. For Hashes it the name of the field. For json it is the path to the json value. &lt;em&gt;attribute&lt;/em&gt; is the alternate name to be given to easily identify the field and index. Attribute type follows the attribute type - type of index to be created for this field (NUMERIC, TEXT and TAG)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Let’s look at a single entry of our document.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; 
  &lt;/span&gt;&lt;span class="nl"&gt;"name"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"The Book"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;text&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"author"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Sam"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; 
  &lt;/span&gt;&lt;span class="nl"&gt;"year"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2020"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;text&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"rating"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;5&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;numeric&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;sortable&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"cover"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"image.png"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"description"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"..."&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;//&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;text&lt;/span&gt;&lt;span class="w"&gt; 
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From the above document let’s create the index for our library dataset. &lt;code&gt;name&lt;/code&gt;, &lt;code&gt;year&lt;/code&gt; and &lt;code&gt;description&lt;/code&gt; fields are indexed as text. &lt;code&gt;rating&lt;/code&gt; is indexed as number and sortable, so we can do sorting on ratings. &lt;/p&gt;

&lt;p&gt;Following command creates all the indexes  we need with name &lt;code&gt;idx:books&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;FT&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;CREATE&lt;/span&gt; &lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;books&lt;/span&gt; &lt;span class="nx"&gt;ON&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt; &lt;span class="nx"&gt;PREFIX&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="nx"&gt;book&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;SCHEMA&lt;/span&gt; &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="nx"&gt;AS&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="nx"&gt;TEXT&lt;/span&gt; &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;author&lt;/span&gt; &lt;span class="nx"&gt;AS&lt;/span&gt; &lt;span class="nx"&gt;author&lt;/span&gt; &lt;span class="nx"&gt;TEXT&lt;/span&gt; &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;rating&lt;/span&gt; &lt;span class="nx"&gt;AS&lt;/span&gt; &lt;span class="nx"&gt;rating&lt;/span&gt; &lt;span class="nx"&gt;NUMERIC&lt;/span&gt; &lt;span class="nx"&gt;SORTABLE&lt;/span&gt; &lt;span class="nx"&gt;$&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="nx"&gt;AS&lt;/span&gt; &lt;span class="nx"&gt;description&lt;/span&gt; &lt;span class="nx"&gt;TEXT&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Queries
&lt;/h3&gt;

&lt;p&gt;Now we can start querying using &lt;code&gt;SEARCH&lt;/code&gt; Operation.&lt;/p&gt;

&lt;p&gt;Simple Search on the book index. This returns all the json records with the word ‘Kaz’ indexed in any of the ‘TEXT’ attribute.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;FT&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SEARCH&lt;/span&gt; &lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;books&lt;/span&gt; &lt;span class="nx"&gt;Kaz&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Output&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_5zwvgsJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3dcxo88kgdfkkoyaybbz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_5zwvgsJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/3dcxo88kgdfkkoyaybbz.png" alt="FT.SEARCH" width="880" height="208"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To search a word only in a single attribute use &lt;code&gt;@{attribute-name}:{word}&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;FT&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SEARCH&lt;/span&gt; &lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;books&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;@description:Kaz&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To select fields to be returned use &lt;code&gt;RETURN {count} {fields...}&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;FT&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SEARCH&lt;/span&gt; &lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;books&lt;/span&gt; &lt;span class="nx"&gt;Kaz&lt;/span&gt; &lt;span class="nx"&gt;RETURN&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="nx"&gt;author&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Output&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--StAE6UXq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tqv4qfnk09kqmjeyl2qs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--StAE6UXq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/tqv4qfnk09kqmjeyl2qs.png" alt="Search with RETURN" width="880" height="205"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Sorting&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;To sort the output according to the rating we can use &lt;code&gt;SORTBY&lt;/code&gt; and &lt;code&gt;ASC&lt;/code&gt;/ &lt;code&gt;DESC&lt;/code&gt; to sort in ascending order or descending order.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;FT&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;SEARCH&lt;/span&gt; &lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;books&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;SORTBY&lt;/span&gt; &lt;span class="nx"&gt;rating&lt;/span&gt; &lt;span class="nx"&gt;DESC&lt;/span&gt; &lt;span class="nx"&gt;RETURN&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="nx"&gt;name&lt;/span&gt; &lt;span class="nx"&gt;rating&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Output&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6ZXOmIrF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q54yj4g0t93xkksp0tsu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6ZXOmIrF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q54yj4g0t93xkksp0tsu.png" alt="SORTBY" width="880" height="517"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There is more cool stuff you can do with &lt;code&gt;SEARCH&lt;/code&gt;. Check out more commands &lt;a href="https://redis.io/commands/ft.search/"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;
  
  
  Aggregation
&lt;/h3&gt;

&lt;p&gt;&lt;code&gt;AGGREGATE&lt;/code&gt; extends the capability of full text search module. &lt;strong&gt;Aggregations&lt;/strong&gt; can be done on the data instead of simply fetching the data using &lt;code&gt;SEARCH&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Explaining the entire aggregation would be so long and out of scope of this article. But to understand the flexibility let’s look at some of requirement for out library application and solve it.&lt;/p&gt;

&lt;p&gt;I want to find the top 5 authors I read most. Following &lt;code&gt;AGGREGATE&lt;/code&gt; query will fetch the top authors I read most.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight jsx"&gt;&lt;code&gt;&lt;span class="nx"&gt;FT&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;AGGREGATE&lt;/span&gt; &lt;span class="nx"&gt;idx&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="nx"&gt;books&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="nx"&gt;GROUPBY&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;author&lt;/span&gt; &lt;span class="nx"&gt;REDUCE&lt;/span&gt; &lt;span class="nx"&gt;COUNT&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="nx"&gt;AS&lt;/span&gt; &lt;span class="nx"&gt;no_of_books&lt;/span&gt; &lt;span class="nx"&gt;SORTBY&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;@&lt;/span&gt;&lt;span class="nd"&gt;no_of_books&lt;/span&gt; &lt;span class="nx"&gt;DESC&lt;/span&gt; &lt;span class="nx"&gt;LIMIT&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Output&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tAkQDs-Y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/23kk52813owe898u9g9l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tAkQDs-Y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/23kk52813owe898u9g9l.png" alt="FT.AGGREGATE" width="880" height="320"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Looks like I am fan of Leigh Bardugo (Which is absolutely correct).&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;AGGREGATE&lt;/code&gt; - Aggregation query&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;GROUPBY&lt;/code&gt; - Group by operator to group all the docs with same author

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;REDUCE&lt;/code&gt; - As the name suggest &lt;em&gt;REDUCE&lt;/em&gt; is used on top of Grouped docs to reduce the docs in to a singe doc.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;COUNT&lt;/code&gt; - Function to be executed on Grouped docs to reduce in to a single. &lt;em&gt;count&lt;/em&gt; returns the number of records in a group. &lt;em&gt;AS&lt;/em&gt; can be used to give a name for the value.&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;SORTBY&lt;/code&gt; - To sort the record on a sortable attribute. In this case it is the calculated value &lt;em&gt;no_of_books.&lt;/em&gt; The *&lt;em&gt;format of *SORTBY&lt;/em&gt; is little different from the &lt;code&gt;SEARCH&lt;/code&gt; query, here we have to mention the &lt;em&gt;nargs&lt;/em&gt; (number of arguments following &lt;em&gt;SORTBY&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;LIMIT&lt;/code&gt; - Limits the number of documents returned. We can paginate the result by providing the &lt;em&gt;offset&lt;/em&gt; value after &lt;em&gt;LIMIT&lt;/em&gt; and number of documents to be returned after &lt;em&gt;offset&lt;/em&gt;.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Check out this &lt;a href="https://github.com/samthom/my-library"&gt;repo&lt;/a&gt; for nodejs implementation of Redis full text search queries in this article.&lt;/p&gt;

&lt;h3&gt;
  
  
  Conclusion
&lt;/h3&gt;

&lt;p&gt;Redis is a full fledged no-sql database with reliability and flexibility. Redis modules makes Redis more powerful and usable. Since it’s an in-memory database your queries can achieve crazy response times.&lt;/p&gt;




&lt;p&gt;This post is in collaboration with Redis.&lt;br&gt;
Try &lt;a href="https://redis.com/try-free/"&gt;Redis Cloud&lt;/a&gt; for free&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=vyxdC1qK4NE"&gt;Redis Enterprise&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://developer.redis.com/"&gt;Redis Developer Hub&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://redis.io/docs/stack/insight/"&gt;Redis Insight&lt;/a&gt;&lt;/p&gt;

</description>
      <category>redis</category>
      <category>database</category>
      <category>javascript</category>
      <category>node</category>
    </item>
    <item>
      <title>Using private docker registry inside kubernetes</title>
      <dc:creator>Sam</dc:creator>
      <pubDate>Fri, 27 May 2022 05:35:33 +0000</pubDate>
      <link>https://dev.to/samthom/using-private-docker-registry-inside-kubernetes-5a32</link>
      <guid>https://dev.to/samthom/using-private-docker-registry-inside-kubernetes-5a32</guid>
      <description>&lt;p&gt;Configure a customer k8s cluster with Digital Ocean Container Registry. &lt;/p&gt;

&lt;h2&gt;
  
  
  Requirements
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;  Kubernetes cluster (Access to the cluster via &lt;em&gt;kubectl&lt;/em&gt;)&lt;/li&gt;
&lt;li&gt;  Private docker registry (I use Digital Ocean for demo)&lt;/li&gt;
&lt;li&gt;  Docker image&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Accessing public images in a public docker registry like &lt;strong&gt;Dockerhub&lt;/strong&gt; is the default behaviour of a kubernetes cluster, unless you want to integrate your own private registry to access private docker images for obvious security reasons. Cloud service providers like AWS, Digital Ocean provides easy integration between own docker registry to managed kubernetes.&lt;br&gt;&lt;br&gt;
But configuring a &lt;strong&gt;baremetal&lt;/strong&gt; kubernetes cluster to access your private registry comes with couple of steps including updating the deployment/pod yaml. I am using digital ocean docker registry for the reference. But steps are same for most of the providers.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you don't have a cluster for demo. Check out &lt;a href="https://kind.sigs.k8s.io/"&gt;Kind&lt;/a&gt;. Kind helps you to run a kubernetes cluster locally in minutes. Or else you can use Katacoda or &lt;a href="https://labs.play-with-k8s.com/"&gt;Play with kubernetes&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  Step 1
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Dockerconfig.json
&lt;/h3&gt;

&lt;p&gt;First we have to get the cluster configured to authenticate to the private registry. A Kubernetes cluster uses the Secret of &lt;code&gt;kubernetes.io/dockerconfigjson&lt;/code&gt; type to authenticate with a container registry to pull a private image. We can do it in two methods. First method is to use the &lt;em&gt;config.json&lt;/em&gt; file and the second method requires your username, password and email. &lt;br&gt;
In digital ocean container registry you can download a read-only config file at container registry home &lt;em&gt;Actions&lt;/em&gt; button. The same file can be found in &lt;code&gt;~/.docker/config.json&lt;/code&gt; when you login in to docker registry in your local machine. &lt;/p&gt;
&lt;h4&gt;
  
  
  Using &lt;em&gt;config.json&lt;/em&gt;
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl create secret generic registry-credential &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--from-file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;.dockerconfigjson&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;path/to/.docker/config.json&amp;gt; &lt;span class="se"&gt;\&lt;/span&gt;
    &lt;span class="nt"&gt;--type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;kubernetes.io/dockerconfigjson
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;or&lt;/p&gt;
&lt;h4&gt;
  
  
  Using docker credentials
&lt;/h4&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl create secret docker-registry registry-credential &lt;span class="nt"&gt;--docker-server&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;your-registry-server&amp;gt; &lt;span class="nt"&gt;--docker-username&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;your-name&amp;gt; &lt;span class="nt"&gt;--docker-password&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;your-pword&amp;gt; &lt;span class="nt"&gt;--docker-email&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;your-email&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;


&lt;p&gt;Inspect created secret&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get secret registry-credential &lt;span class="nt"&gt;--output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The output is similar to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Secret&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="s"&gt;...&lt;/span&gt;
  &lt;span class="s"&gt;name&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt; &lt;span class="s"&gt;registry-credential&lt;/span&gt;
  &lt;span class="s"&gt;...&lt;/span&gt;
&lt;span class="na"&gt;data&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;.dockerconfigjson&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;eyJodHRwczovL2luZGV4...&lt;/span&gt;
&lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;kubernetes.io/dockerconfigjson&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The value of the &lt;code&gt;.dockerconfigjson&lt;/code&gt; field is a base64 representation of your Docker credentials. To convert the data into readable format use the following command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get secret registry-credential &lt;span class="nt"&gt;--output&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"jsonpath={.data.&lt;/span&gt;&lt;span class="se"&gt;\.&lt;/span&gt;&lt;span class="s2"&gt;dockerconfigjson}"&lt;/span&gt; | &lt;span class="nb"&gt;base64&lt;/span&gt; &lt;span class="nt"&gt;--decode&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Editing the pod
&lt;/h3&gt;

&lt;p&gt;Once the secret is created we can update our pod config to use the created secret to pull images. Update the spec session of your pod as follows.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;containers&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;private-reg-container&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;&amp;lt;your-private-image&amp;gt;&lt;/span&gt;
  &lt;span class="na"&gt;imagePullSecrets&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;registry-credential&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To pull the image from the private registry, Kubernetes needs credentials. The &lt;code&gt;imagePullSecrets&lt;/code&gt; field in the configuration file specifies that Kubernetes should get the credentials from a Secret named &lt;code&gt;registry-credential&lt;/code&gt;.&lt;br&gt;
Create a Pod that uses your Secret, and verify that the Pod is running&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; pod.yaml
kubectl get pod &amp;lt;pod-name&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you don't want to add &lt;code&gt;imagePullSecrets&lt;/code&gt; to your pod config or need to set different registries per namespace as default then go to &lt;strong&gt;step 3&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step 3
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Adding image pull secretes to service account
&lt;/h3&gt;

&lt;p&gt;If you want to get a preview about service accounts checkout this &lt;a href="https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#use-the-default-service-account-to-access-the-api-server"&gt;doc&lt;/a&gt;&lt;br&gt;
To add our new secret to the namespace we have to modify the service account and push our new secret name to the &lt;em&gt;imagePullSecret&lt;/em&gt; array inside the service account.&lt;br&gt;
We can download the service account manifest by&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get serviceaccounts default &lt;span class="nt"&gt;-o&lt;/span&gt; yaml &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; ./service-account.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;then update it as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ServiceAccount&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;creationTimestamp&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;2015-08-07T22:02:39Z&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default&lt;/span&gt;
  &lt;span class="na"&gt;namespace&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default&lt;/span&gt;
  &lt;span class="na"&gt;uid&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;052fb0f4-3d50-11e5-b066-42010af0d7b6&lt;/span&gt;
&lt;span class="na"&gt;secrets&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;default-token-uudge&lt;/span&gt;
&lt;span class="na"&gt;imagePullSecrets&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
&lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;registry-credential&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally replace the service account with updated manifest file&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl replace serviceaccount default &lt;span class="nt"&gt;-f&lt;/span&gt; ./service-account.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, when a new Pod is created in the current namespace and using the default ServiceAccount, the new Pod has its &lt;code&gt;spec.imagePullSecrets&lt;/code&gt; field set automatically.&lt;/p&gt;




&lt;p&gt;References:&lt;br&gt;
&lt;a href="https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry/"&gt;Pull an Image from a Private Registry&lt;/a&gt;&lt;br&gt;
&lt;a href="https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/#add-image-pull-secret-to-service-account"&gt;Add image pull secret to service account&lt;/a&gt;&lt;br&gt;
Add image pull secret to service account&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>docker</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
