<?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>Forem: Abdulla T</title>
    <description>The latest articles on Forem by Abdulla T (@abbadev).</description>
    <link>https://forem.com/abbadev</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%2F84827%2F66eb3722-d660-4f4a-a271-14841cdba19e.jpeg</url>
      <title>Forem: Abdulla T</title>
      <link>https://forem.com/abbadev</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/abbadev"/>
    <language>en</language>
    <item>
      <title>Taking the OpenJS Node.js Services Developer Certification Exam</title>
      <dc:creator>Abdulla T</dc:creator>
      <pubDate>Mon, 03 May 2021 16:33:22 +0000</pubDate>
      <link>https://forem.com/abbadev/taking-the-openjs-node-js-services-developer-certification-exam-1pmj</link>
      <guid>https://forem.com/abbadev/taking-the-openjs-node-js-services-developer-certification-exam-1pmj</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;My review on taking the JSNSD (OpenJS Node.js Services Developer) exam, its preparation course, and some useful tips that helped me pass the exam.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--llDAwrKp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hlff8t08akm060xlongp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--llDAwrKp--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hlff8t08akm060xlongp.png" alt="JSNSD Logo"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Earlier this week, I set up an isolated corner in my living room and took the 2-hour online exam for the OpenJS Node.js Services Developer (JSNSD) certification.&lt;/p&gt;

&lt;p&gt;In this post, I would like to talk about the exam itself, my experience and preparation for it, and discuss if it's worth it for you too.&lt;/p&gt;

&lt;p&gt;I won't be sharing information about the exam questions as this is against the exam's confidentiality agreement. However, I will talk more about the experience and the preparation course for this exam offered by the Linux Foundation.&lt;/p&gt;

&lt;h4&gt;
  
  
  Who offers this certificate?
&lt;/h4&gt;

&lt;p&gt;This certification is offered by the &lt;a href="https://openjsf.org/"&gt;OpenJS&lt;/a&gt; Foundation, a leading foundation that supports the growth and governance of many NodeJS open source projects such as Node.js, Electron, jQuery, and Webpack.&lt;/p&gt;

&lt;p&gt;The exam is delivered through &lt;a href="https://linuxfoundation.org/"&gt;The Linux Foundation&lt;/a&gt;, which is also known for delivering other popular certificates such as the Certified Kubernetes Administrator (CKA) and the Linux Foundation Certified Engineer (LFCE) as well as other types of certificates. So, this is probably the most legitimate Node.js certification in the industry nowadays.&lt;/p&gt;

&lt;p&gt;There are two types of &lt;a href="https://openjsf.org/certification/"&gt;Node.js certificates&lt;/a&gt; offered:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;OpenJS Node.js Services Developer (JSNSD) (&lt;strong&gt;I took this one&lt;/strong&gt;)

&lt;ul&gt;
&lt;li&gt;Focuses on creating REST API services and security of your services against malicious user input.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;OpenJS Node.js Application Developer (JSNAD)

&lt;ul&gt;
&lt;li&gt;Focuses on the core modules of Node.js such as the file system, buffers, streams, child processes.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I'll be talking more in-depth about the JSNSD, but some of the tips would also apply if you take the JSNAD.&lt;/p&gt;

&lt;h4&gt;
  
  
  Exam Format and style
&lt;/h4&gt;

&lt;p&gt;The exam is a performance-based exam (like a practical lab), which means you will take your test on a VM online to write some code and create Node.js applications.&lt;/p&gt;

&lt;p&gt;Each task will require you to build a simple Node.js app that implements a specific requirement only (for example, an HTTP method that should return a particular HTTP response and status).&lt;/p&gt;

&lt;p&gt;For the JSNSD, you can implement your solution in any way you like. You won't be assessed on how you implement the solution, but on how your application responds to their various HTTP requests.&lt;/p&gt;

&lt;p&gt;The exam is 2 hours long, and you will solve it by connecting to a remote desktop Linux environment virtual machine. The VM for the JSNSD is currently using CentOS with a GUI. The VM comes already pre-installed with node, npm, Postman, Visual Studio Code, and even WebStorm IDE. So, you don't need to install anything on the virtual machine you will be testing on.&lt;/p&gt;

&lt;p&gt;You are allowed to search on Google and browse any Node.js documentation through the chrome browser of the remote desktop. You can access any documentation, npm modules docs, and even GitHub. However, StackOverFlow and other Stack Exchange websites are blocked during the exam.&lt;/p&gt;

&lt;h4&gt;
  
  
  Motivation for the exam and its value
&lt;/h4&gt;

&lt;p&gt;I've been using Node.js for over four years, both at work and on my side projects.&lt;/p&gt;

&lt;p&gt;I first heard about this certification from Twitter early in 2020, and what greatly interested me was the style of the exam. I thought it would be an exciting challenge to try out, so I decided to take the JSNSD because it's more in line with what I work with more often.&lt;/p&gt;

&lt;p&gt;I've read online about some people who have taken one or both certificates to improve their Node.js skills or because their employers asked them (for whatever reason). At the moment, I haven't found any information if this certificate brings a lot of value to the employer as there is no organizational benefit (partner benefits) to the company if their engineers held this certificate.&lt;/p&gt;

&lt;p&gt;I usually think that coding skills are better validated by building a challenging project instead of doing a certification in some scenarios.  However, I don't want to ignite the debate of whether coding languages certifications are worth it. I would compare these Node.js certifications to the Java associate certifications from Oracle. Some people have found great value by being Java certified in helping them at least get their foot in the door for an interview. The Node.js certifications are barely two years old, so they are not as well known in the industry as the Java certifications, but they might still be a good conversation starter in an interview.&lt;/p&gt;

&lt;h4&gt;
  
  
  Exam and companion study course cost ($$$)
&lt;/h4&gt;

&lt;p&gt;So, the reason I talked about motivation and value above is because the cost of this certification is an eye-watering USD 300, which is quite expensive for someone who will pay for it from their pocket (like me). If you decide to buy the preparation companion course, you can buy the &lt;a href="https://training.linuxfoundation.org/training/node-js-application-development-lfs211-jsnad-exam-bundle/"&gt;bundle&lt;/a&gt; which costs USD 499 in total at the moment of writing this blog post. This price is for one of the certificates (either the JSNSD or JSNAD).&lt;/p&gt;

&lt;p&gt;Thankfully, I bought this exam (and course) at a massive discount during a sale season run by The Linux Foundation. The last discount they had in early April 2021 was offering the exam for $99. They also offered both the exam and preparation course bundle for $149. So, I strongly suggest subscribing to The Linux Foundation email updates and wait for their next sale season, or &lt;a href="https://training.linuxfoundation.org/training/convince-your-boss/?id=bundle-12583"&gt;convince your boss&lt;/a&gt; to pay for it.&lt;/p&gt;

&lt;p&gt;When you purchase the exam, you get a voucher that is valid for one year. You can schedule your exam anytime during this year. You also get a free retake if you fail your first attempt at the exam.&lt;/p&gt;

&lt;p&gt;If you also purchase the course, you will get 1-year access to the course.&lt;/p&gt;

&lt;p&gt;Before you buy the exam, make sure you read the &lt;a href="https://docs.linuxfoundation.org/tc-docs/certification/faq-openjs"&gt;list of faqs&lt;/a&gt; for Id and system requirements and whether you are not currently living in a sanctioned country.&lt;/p&gt;

&lt;h4&gt;
  
  
  Preparing for the exam
&lt;/h4&gt;

&lt;p&gt;Initially, when I bought the exam, there was no companion preparation course, so I referred to their list of &lt;a href="https://docs.linuxfoundation.org/tc-docs/certification/faq-openjs#is-there-training-to-prepare-for-the-certification-exam"&gt;suggested references&lt;/a&gt;, which included:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.packtpub.com/product/node-cookbook-fourth-edition/9781838558758"&gt;Node Cookbook&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://nodeschool.io/"&gt;https://nodeschool.io/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Node.js documentation&lt;/li&gt;
&lt;li&gt;Any Node.js web framework documentation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;However, while I read some chapters and sections from the above resources, I procrastinated on reading more. I didn't feel confident enough whether I knew everything they were going to test me, and information was scarce. A few months later, The Linux Foundation launched a couple of training courses for these exams, so I bought the &lt;a href="https://training.linuxfoundation.org/training/node-js-services-development-lfw212/"&gt;Node.js Services Development (LFW212) course&lt;/a&gt; and studied it.&lt;/p&gt;

&lt;p&gt;The course was sufficient for me as the only study material I needed for the exam. In total, it took me a couple of weekends to finish the whole course. The list of chapters is listed on the course page &lt;a href="https://training.linuxfoundation.org/training/node-js-services-development-lfw212/"&gt;here&lt;/a&gt;. The course is targeted to intermediate-level Node.js developers, so if you are a total beginner to backend and Node.js, it might take you a bit longer.&lt;/p&gt;

&lt;h4&gt;
  
  
  Course review
&lt;/h4&gt;

&lt;p&gt;The course is a written format course (so no video or recordings to watch). It was split into ten chapters with 1 or 2 labs for each chapter. Each lab is a written task (which is similar to the exam task), and you need to download a few JS files that contain some required code for each lab. One of the JS files is a unit testing suite that you can run at the end of your lab to validate if you've implemented the lab requirements correctly.&lt;/p&gt;

&lt;p&gt;Here are the pros and cons of the course based on my own opinion:&lt;/p&gt;

&lt;h6&gt;
  
  
  Pros
&lt;/h6&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;I enjoyed the course and mainly because the course &lt;a href="https://twitter.com/davidmarkclem"&gt;author&lt;/a&gt; focused on two web frameworks (&lt;a href="https://expressjs.com/"&gt;Express&lt;/a&gt; and &lt;a href="https://www.fastify.io/"&gt;Fastify&lt;/a&gt;) and implemented most examples in each framework to compare the implementation to each other.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The author also did an excellent job explaining the memory leak issues that can arise when using the Express framework with async-await (without a try-catch), so he provided the express examples using callback-style functions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You have access to the &lt;a href="https://forum.linuxfoundation.org/categories/lfw212-class-forum"&gt;forum&lt;/a&gt; to ask questions if you are stuck.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The course is sufficient for the exam but is still well-rounded enough to cover some basics of REST API design in Node.js.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h6&gt;
  
  
  Cons
&lt;/h6&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;For an expensive course, I was hoping that the labs can be solved and validated online rather than downloading all files and setting up my local environment.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The topics covered in the Web Security chapters are disappointingly basic and limited. Here's what was covered in the course:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Preventing HTTP Parameter Pollution&lt;/li&gt;
&lt;li&gt;Validating API requests and response body and structure&lt;/li&gt;
&lt;li&gt;Blocking a specific IP from your application on the code level.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;&lt;p&gt;I found the sidebar navigation menu quite annoying as a lot of the sublinks had the same title, so finding a specific part you've read earlier is tricky.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I wish the course had covered more advanced security topics, and the certificate is evolved (or have an advanced level) to test for a broader range of security threats that can affect any Node.js application.&lt;/p&gt;

&lt;h4&gt;
  
  
  Scheduling the exam
&lt;/h4&gt;

&lt;p&gt;Scheduling the exam was straightforward through the Linux Foundation Portal. I just selected a date and time 2 days in advance. The date and time selection dropdown is super slow, but you can see different daily availabilities on different hours once you get it loaded. The test itself is proctored by &lt;a href="https://www.psionline.com/en-gb/"&gt;PSI&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;You will also be asked to download a specific chrome extension so that the proctor can monitor your screen.&lt;/p&gt;

&lt;h4&gt;
  
  
  Taking the exam
&lt;/h4&gt;

&lt;p&gt;For the exam, I set up an isolated, comfortable free-of-clutter desk in my living room. I logged in 15 minutes before my exam starts and waited for the proctor to show up. The proctor asked me to show my primary ID using the webcam and do a 360 tour of the room with my webcam. After going through some extra screen-sharing checks, I was allowed to start the exam right away.&lt;/p&gt;

&lt;p&gt;The remote desktop is accessed through my laptop's Chrome browser tab. The VM's desktop size is viewed full screen on my browser tab. Inside the VM, there is a Chrome browser (which belongs to the VM) that is already open with the list of tasks you have to do. I opened the WebStorm IDE, which immediately opened the list of folders for all of the tasks. I just jumped between each folder in the IDE terminal. I also opened some documentation references via the chrome browser of the VM (not my machine).&lt;/p&gt;

&lt;p&gt;The exam went smoothly with no latency issues, and I managed to complete all the tasks in an hour and a half, and I spent the remaining half an hour testing my code again and make sure there were no hiccups.&lt;/p&gt;

&lt;p&gt;The results were emailed to me after 24 hours, and I successfully passed the test with a score of 94%. Unfortunately, there is no feedback on the scoring, so I don't know which part I might have implemented wrong.&lt;/p&gt;

&lt;p&gt;You also get a digital badge via Credly and a link to a certificate validation tool. The certificate is valid for three years.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rl6wfnTk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/irsq0ns5qw0skjppp8rm.jpeg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rl6wfnTk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/irsq0ns5qw0skjppp8rm.jpeg" alt="My Desk Setup"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  Final thoughts
&lt;/h4&gt;

&lt;p&gt;If you are a total beginner to the backend or Node.js, I think the course or exam will be challenging to tackle. If you've already worked with Node.js before, this is an easy exam.&lt;/p&gt;

&lt;p&gt;The exam can be an interesting personal learning milestone and help you showcase something to get a first programming job in a Node.js company.&lt;/p&gt;

&lt;p&gt;The companion training course is a time saver to help you study faster instead of referring to multiple references. Still, if you want to budget your money and already have some Node.js experience, you can take the exam first as you have a free retake. You can then decide if you want to purchase the course or not.&lt;/p&gt;

&lt;p&gt;Nevertheless, I learned a lot from this course. I've worked with Express a lot before, so I primarily learned about Fastify through this course, and I liked it, so now I'll mainly be using Fastify in my future Node.js projects.&lt;/p&gt;

&lt;h4&gt;
  
  
  Tips summary
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Don't forget to cover your Javascript and Node.js basics (e.g., async-await, promises, set timeout, callbacks, package.json, dependencies, npm)&lt;/li&gt;
&lt;li&gt;Learn a framework (e.g., Express or Fastify). Implementing the exam tasks with a &lt;a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Node_server_without_framework"&gt;vanilla&lt;/a&gt; Node.js server will take you longer.&lt;/li&gt;
&lt;li&gt;Make sure all of your tasks can start running with &lt;code&gt;npm start&lt;/code&gt; command.&lt;/li&gt;
&lt;li&gt;Don't memorize the code. It's an open book exam, so you can refer to references. However, you will need to study the concepts before. The exam time is not sufficient for you to learn how to implement a GET method if you've never implemented one before.&lt;/li&gt;
&lt;li&gt;If you plan to take both certificates, I would recommend starting with the JSNAD if you want to cover most of the Node.js core modules in your learning.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bonus tip&lt;/strong&gt;: The Linux Foundation is currently offering a limited-time offer for you to preview the Node.js Certification Testing Environment. You can get a good feel of how the VM test looks like, and you can do a few sample questions. No proctor, and it's not assessed. You can apply for it &lt;a href="https://training.linuxfoundation.org/announcements/apply-here-for-the-node-js-certification-environment-preview-beta/"&gt;here&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I also found a few extra tips in this &lt;a href="https://dev.to/kryz/node-js-certification-first-impressions-21a1"&gt;post&lt;/a&gt; helpful.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Thank you so much&lt;/strong&gt; for taking the time to read through my article.&lt;/p&gt;

&lt;p&gt;If you enjoyed it or have a question, please let me know in a comment below or reach me on &lt;a href="https://twitter.com/abbadev"&gt;Twitter&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>node</category>
      <category>certification</category>
    </item>
    <item>
      <title>Using PartiQL to query AWS DynamoDb in Javascript</title>
      <dc:creator>Abdulla T</dc:creator>
      <pubDate>Mon, 15 Feb 2021 11:12:22 +0000</pubDate>
      <link>https://forem.com/aws-builders/using-partiql-to-query-aws-dynamodb-in-javascript-2gp6</link>
      <guid>https://forem.com/aws-builders/using-partiql-to-query-aws-dynamodb-in-javascript-2gp6</guid>
      <description>&lt;p&gt;AWS recently &lt;a href="https://aws.amazon.com/about-aws/whats-new/2020/11/you-now-can-use-a-sql-compatible-query-language-to-query-insert-update-and-delete-table-data-in-amazon-dynamodb/"&gt;announced&lt;/a&gt; a new feature to give users the ability to use PartiQL, which is an SQL compatible query language to work with data in Amazon DynamoDB.&lt;/p&gt;

&lt;p&gt;When this was launched, I was initially excited because it means I can write my queries in a more familiar way of SQL-like queries rather than using the Document Client API.&lt;/p&gt;

&lt;p&gt;In this article, I would like to compare querying and inserting data into dynamoDb using PartiQL vs. using the Document Client. I will also be touching on the performance and features of using either approach. I will be using the AWS Javascript SDK throughout my Node.js code examples.&lt;/p&gt;

&lt;h3&gt;
  
  
  Quick introduction to the Document Client and PartiQL
&lt;/h3&gt;

&lt;h6&gt;
  
  
  PartiQL
&lt;/h6&gt;

&lt;p&gt;Amazon DynamoDB supports PartiQL, an SQL-compatible query language to select, insert, update, and delete data in DynamoDB. PartiQL operations provide the same availability, latency, and performance as the other DynamoDB data operations. For the PartiQL specification and a tutorial on the core query language, see the &lt;a href="https://partiql.org/docs.html"&gt;PartiQL documentation&lt;/a&gt;.&lt;/p&gt;

&lt;h6&gt;
  
  
  Document Client
&lt;/h6&gt;

&lt;p&gt;DynamoDb Document Client simplifies working with the DynamoDB methods by abstracting away the notion of attribute values. Basically, you can use Javascript objects directly and pass them to DynamoDB methods, and the Document Client will map the Javascript types to the DynamoDB tables.&lt;/p&gt;

&lt;p&gt;For example, to get an item from a DynamoDb table, this example below will show the differences in constructing the param object between the Document Client and the DynamoDb direct method.&lt;/p&gt;

&lt;p&gt;This example uses the DynamoDB documentClient &lt;code&gt;get&lt;/code&gt; method.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;documentClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;AWS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DynamoDB&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DocumentClient&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;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;TableName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Movies&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&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;year&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2020&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;title&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;A movie&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="nx"&gt;documentClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&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;err&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;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;else&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;data&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;And this example below is using the DynamoDB &lt;code&gt;getItem&lt;/code&gt; method directly.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dynamoDb&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;AWS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DynamoDB&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;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;TableName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Movies&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&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;year&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;
                &lt;span class="na"&gt;N&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;2020&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;title&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;S&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;A movie&lt;/span&gt;&lt;span class="dl"&gt;"&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;span class="nx"&gt;dynamoDb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;getItem&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;err&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&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;err&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;err&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;else&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;data&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;h3&gt;
  
  
  Getting started
&lt;/h3&gt;

&lt;p&gt;To follow along with this article and try the examples on your machine, you can clone this Node.js &lt;a href="https://github.com/abbathaw/dynamoDb-partiQL-javascript"&gt;github repo&lt;/a&gt; and run the getting started command, which will set up a DynamoDb table and upload sample data to that table. The table and sample data is almost similar to the AWS docs &lt;a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/GettingStarted.Js.01.html"&gt;example&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The getting-started command of my example repo will create a simple DynamoDb table called Movies that has a list of movies with the following attributes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Partition key: year (number)&lt;/li&gt;
&lt;li&gt;Sort key: title (string)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iYuev5-m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/vblcz1tk8qi82ut5m3qp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iYuev5-m--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/vblcz1tk8qi82ut5m3qp.png" alt="Creating a DynamoDb table called Movies"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I created the table in the US-East-1 region, so if you are following along, you will need to update your region in the example code if you use a different region. At the moment of writing this post, PartiQL is supported in 23 regions as per the announcement &lt;a href="https://aws.amazon.com/about-aws/whats-new/2020/12/partiql-for-dynamodb-now-is-supported-in-23-aws-regions/"&gt;post&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you've setup everything, you should see the following data in your Movies table preview in the console UI.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Tgi-IZy6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/013s44b0snrgm9ih4rda.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Tgi-IZy6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/013s44b0snrgm9ih4rda.png" alt="Preview of dynamoDb Movies table"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Querying the data using PartiQL Editor in the console
&lt;/h3&gt;

&lt;p&gt;Before writing any code, let's test the data using the PartiQL editor in the console UI. You will need to use the new console UI preview to see this view.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--vVKWSA6D--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/j3klcdh1msyd2gpkuc2h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--vVKWSA6D--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/j3klcdh1msyd2gpkuc2h.png" alt="Testing the data using PartiQL Editor in the console"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can start by writing a simple Select Query as shown below to query all movies from the year 2010.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;Movies&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="nv"&gt;"year"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2010&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above will query the movies table and filter it with the Partition Key "year". Since the partition key is a number, we can pass 2010 as a number without quotes.&lt;/p&gt;

&lt;p&gt;Another example below is querying all the movies from 2010, where the movie title contains the word 'and'.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="n"&gt;Movies&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="nv"&gt;"year"&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;2010&lt;/span&gt;
  &lt;span class="k"&gt;and&lt;/span&gt; &lt;span class="k"&gt;contains&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;"title"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'and'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Important tips to keep in mind when writing PartiQL statements
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;Use &lt;strong&gt;single quotes&lt;/strong&gt; for strings.&lt;/li&gt;
&lt;li&gt;Use &lt;strong&gt;double-quotes&lt;/strong&gt; for field names, variables, and reserved words.&lt;/li&gt;
&lt;li&gt;Don't forget to include a &lt;strong&gt;WHERE&lt;/strong&gt; clause condition that specifies a &lt;strong&gt;partition key&lt;/strong&gt; to avoid having your &lt;code&gt;SELECT&lt;/code&gt; statement perform an expensive full table scan. For more information, you can refer to the Select Statement &lt;a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ql-reference.select.html"&gt;reference&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Side Tip&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you are worried about writing PartiQL queries that can run full table scans accidentally, you can set an IAM policy for your user that locks full table scans. Once your policy is set, your query will return an exception. Read more &lt;a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ql-iam.html"&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Using the Javascript SDK to run operations on the table
&lt;/h3&gt;

&lt;p&gt;Now that we have the sample data uploaded in the table and quickly tested the PartiQL editor on the console, let's see how we can use the Javascript SDK to run operations on the table using both the Document Client and the PartiQL statements.&lt;/p&gt;

&lt;p&gt;As mentioned above, you can view all the examples below in full, including the necessary try/catch blocks in this &lt;a href="https://github.com/abbathaw/dynamoDb-partiQL-javascript"&gt;Github repository&lt;/a&gt;. If you are following the setup to run the same examples on your machine, you can run them using the node command. Refer to the repo readme file.&lt;/p&gt;

&lt;h4&gt;
  
  
  Querying the table
&lt;/h4&gt;

&lt;h6&gt;
  
  
  Example query with the Document Client
&lt;/h6&gt;

&lt;p&gt;Let's start with an example of how a query can be done using the Document Client.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="c1"&gt;//query-documentAPI.js&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;documentClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;AWS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DynamoDB&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DocumentClient&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;queryWithDocumentClient&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;year&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;title&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;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;TableName&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Movies&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;ProjectionExpression&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#yr, title, info&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;KeyConditionExpression&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#yr = :yyyy and title = :title&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;ExpressionAttributeNames&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;#yr&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;year&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="p"&gt;},&lt;/span&gt;
        &lt;span class="na"&gt;ExpressionAttributeValues&lt;/span&gt;&lt;span class="p"&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;:yyyy&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;year&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;:title&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;title&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;results&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;documentClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;promise&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;In the above example, we form the params object, which contains the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ProjectionExpression&lt;/code&gt; specifies the attributes you want in the result. In this example, I selected all attributes.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;KeyConditionExpression&lt;/code&gt; specifies the condition we want our query to use. Notice that we've used an alias '#yr' for the key 'year' because 'year' is a &lt;a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ReservedWords.html"&gt;reserved&lt;/a&gt; keyword in DynamoDb.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ExpressionAttributeNames&lt;/code&gt; lets us map the alias '#yr' to the actual word 'year'.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ExpressionAttributeValues&lt;/code&gt; allows us to put the values and map them to the alias keys we wrote in the KeyConditionExpression.&lt;/li&gt;
&lt;/ul&gt;

&lt;h6&gt;
  
  
  Example query with PartiQL
&lt;/h6&gt;

&lt;p&gt;Let's now see how we can write the same query in PartiQL.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="c1"&gt;//query-partiQL.js&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dynamoDB&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;AWS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DynamoDB&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;queryWithPartiQL&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="nx"&gt;year&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;title&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;statement&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`SELECT * FROM Movies WHERE "year" = &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;year&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; and "title" = '&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;' `&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;results&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;dynamoDB&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;executeStatement&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="na"&gt;Statement&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;statement&lt;/span&gt;&lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nx"&gt;promise&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;In the above example, we form our SQL statement as a string and then use &lt;code&gt;executeStatement&lt;/code&gt; method to run this statement. This will return us the item but with the dynamoDb attribute map, so if we want to convert the first item in the results back to a JS object, we can use  &lt;code&gt;AWS.DynamoDB.Converter.unmarshall(results.Items[0])&lt;/code&gt;.&lt;/p&gt;

&lt;h4&gt;
  
  
  Inserting an item to the table
&lt;/h4&gt;

&lt;h6&gt;
  
  
  Example insert item with the Document Client
&lt;/h6&gt;

&lt;p&gt;Let's start with an example of how an insert can be done using the Document Client.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="c1"&gt;//insert-documentAPI.js&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;documentClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;AWS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DynamoDB&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DocumentClient&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;insertWithDocumentClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;movie&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;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="na"&gt;TableName&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Movies&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;movie&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;documentClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;promise&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;movieDetails&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;year&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2020&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;The Big New Movie&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;
        &lt;span class="na"&gt;plot&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Nothing happens at all.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;rating&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;insertWithDocumentClient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;movieDetails&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this approach, inserting a single item with the Document Client is straightforward. We can pass the movie object as a JS object and construct our params object, which we pass to the put method.&lt;/p&gt;

&lt;p&gt;You can also add additional keys to the params object such as &lt;code&gt;ConditionExpression&lt;/code&gt; if you want to have your PutItem operation run only if a specific condition is met, e.g., attribute_not_exists.&lt;/p&gt;

&lt;h6&gt;
  
  
  Example insert item with PartiQL
&lt;/h6&gt;

&lt;p&gt;Moving on to the next example, where we insert the same item with PartiQL. I found this part quite interesting when I was coding this example. Initially, PartiQL was constantly throwing an error for a badly formed statement.&lt;/p&gt;

&lt;p&gt;The main reason for this issue is that the PartiQL statement expects the data to have strings in &lt;strong&gt;single quotes&lt;/strong&gt;, as we mentioned earlier above. However, when you construct a regular JS object and pass it to another method, the strings become contained in double-quotes instead.&lt;/p&gt;

&lt;p&gt;To fix this issue, I parsed the object in a simple DIY custom implementation of a JSON stringifier function, and I modified it to use single quotes instead. I also modified it to escape any single quotes in the text by doubling them. For example, if the movie's title is &lt;code&gt;A bug's life&lt;/code&gt;, it becomes &lt;code&gt;A bug''s life&lt;/code&gt;, which is how single quotes are usually escaped in SQL.&lt;/p&gt;

&lt;p&gt;The code for this stringifier is in the utils folder in my Github repo; however, this is a simple implementation and was made only to demonstrate PartiQL in this blog article, so it doesn't handle a few cases.  You might prefer in production to use a good JS library that can safely handle this string parsing to be compatible with PartiQL statements.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="c1"&gt;//insert-partiQL.js&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;stringify&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../utils/stringify&lt;/span&gt;&lt;span class="dl"&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;dynamoDB&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;AWS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DynamoDB&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;insertWithPartiQL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;movie&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// stringify object to what PartiQL will accept&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;movie&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;dynamoDB&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;executeStatement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="na"&gt;Statement&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`INSERT INTO Movies VALUE &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;
    &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nx"&gt;promise&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;movieDetails&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;year&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2020&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;The Big New Movie&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="p"&gt;:{&lt;/span&gt;
        &lt;span class="na"&gt;plot&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Nothing happens at all.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="na"&gt;rating&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nx"&gt;insertWithPartiQL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;movieDetails&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Batch Insert into a table
&lt;/h4&gt;

&lt;p&gt;In addition to inserting and querying data, let's quickly go over an example for batch insert operations.&lt;/p&gt;

&lt;h6&gt;
  
  
  Example batch insert with the Document Client
&lt;/h6&gt;

&lt;p&gt;In the Document Client, batch insert can be done using the batchWrite method. This method delegates to the &lt;code&gt;AWS.DynamoDB.batchWriteItem&lt;/code&gt; but the advantage of using this Document Client method is that we can use native Javascript types instead of having to specify the DynamoDb attributes types for each field.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="c1"&gt;//batch-documentAPI.js&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;documentClient&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;AWS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DynamoDB&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DocumentClient&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;uploadBatchMoviesData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;listOfMovies&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;items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;listOfMovies&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;movie&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="na"&gt;PutRequest&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;Item&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="na"&gt;year&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;movie&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;year&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                    &lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;movie&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;title&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
                    &lt;span class="na"&gt;info&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;movie&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;info&lt;/span&gt;&lt;span class="dl"&gt;'&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;span class="p"&gt;}&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;items&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="mi"&gt;25&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;upperLimit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;min&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="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;items&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;batch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;items&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slice&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="nx"&gt;upperLimit&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;params&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="na"&gt;RequestItems&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Movies&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;batch&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;documentClient&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;batchWrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;params&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;promise&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;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;listOfMovies&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createFakeMovies&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;uploadBatchMoviesData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;listOfMovies&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From the above example, we first iterate over the array list of all the movies to construct the shape of the &lt;code&gt;PutRequest&lt;/code&gt; body. We then iterate again over this big array of items and slice 25 items for each batch request. This is because a single call to BatchWriteItem can have as many as 25 put or delete requests, and each item can be as large as 400 KB. Therefore, we will batch 25 movies in each call until we upload the whole list.&lt;/p&gt;

&lt;p&gt;The Document Client BatchWrite method delegates to the DynamoDb BatchWriteItem, so there are some caveats which you need to consider:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;BatchWriteItem cannot update items (it will replace the whole existing items), so if you want to update each item individually, use the &lt;code&gt;UpdateItem&lt;/code&gt; method.&lt;/li&gt;
&lt;li&gt;The response you get back from this method will contain an array of unprocessed items if some items failed. However, you will not get an individual response per item. Also, the whole batch write operation might fail even if only one of your items contain a wrong primary key attribute.&lt;/li&gt;
&lt;li&gt;You cannot specify conditions on each put request.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For more information on BatchWriteItem, you can refer to the &lt;a href="https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_BatchWriteItem.html"&gt;docs&lt;/a&gt;.&lt;/p&gt;

&lt;h6&gt;
  
  
  Example batch insert with PartiQL
&lt;/h6&gt;

&lt;p&gt;PartiQL has some advantages here in batch operations compared to the Document Client. The reason for that is that we can write individual statements for insert and updates and then use the &lt;code&gt;batchExecuteStatement&lt;/code&gt; method to run each statement. The other advantage is that we will get an individual response to each statement. However, one limitation is that the entire batch must consist of either read statements or write statements; you cannot mix both in one batch.&lt;/p&gt;

&lt;p&gt;We also have the same limitation of 25 items in each batch request.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="c1"&gt;//batch-partiQL.js&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dynamoDB&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;AWS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DynamoDB&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;listOfMovies&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;uploadBatchWithPartiQL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;listOfMovies&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;statements&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;listOfMovies&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;movie&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;movie&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Statement&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`INSERT INTO Movies VALUE &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;}&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;statements&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="mi"&gt;25&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;upperLimit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;min&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="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;statements&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;batch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;statements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slice&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="nx"&gt;upperLimit&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;response&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;dynamoDB&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;batchExecuteStatement&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;Statements&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;batch&lt;/span&gt;
          &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nx"&gt;promise&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;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;listOfMovies&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createFakeMovies&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;uploadBatchWithPartiQL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;listOfMovies&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Similar to inserting an item using PartiQL, we are stringifying the movie using our custom stringifier method to ensure single quotes are used for strings in the object. We are then simply constructing an SQL statement that we then batch into an array of 25 items each and pass it to the &lt;code&gt;batchExecuteStatement&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;Keep in mind that in both PartiQL or Document Client, if the same batch (the 25 items batch) has a duplicate primary key and sort key, then that whole batch call will fail.&lt;/p&gt;

&lt;p&gt;On the other hand, if the duplicate item was inserted in a separate batch, one of the differences between both is that an insert statement using PartiQL batchExecuteStatement will fail for that statement only if the item already exists in the table (same Partition key and sort key). This is not the case with the Document Client batchWrite, which will actually replace the whole item even if it exists.&lt;/p&gt;

&lt;h3&gt;
  
  
  Performance Comparision
&lt;/h3&gt;

&lt;p&gt;In short, there is no noticeable performance difference between Document Client and PartiQL. Both perform fast and almost take the same duration for the same type of operations. If you run the examples on your machine, you can also see the difference between each operation. I've added a console.log time to most files.&lt;/p&gt;

&lt;p&gt;PartiQL would perform as fast as using Document Client, and if you run the same operation multiple times, the differences are less than 100-300 ms between each operation, and in some cases, they would run at the same speed or faster.&lt;/p&gt;

&lt;p&gt;One thing to note is the way I wrote my batch write statements examples above will run each batch statement sequentially since we are using a for-loop. However, suppose your table uses on-demand capacity, or you've provisioned your table with a higher write capacity. In that case, it will be very performant for you to write it in a concurrent approach using &lt;code&gt;Promises.all&lt;/code&gt; as the example code shown below.&lt;/p&gt;

&lt;p&gt;Previously, both Document Client and PartiQL would take 23 seconds to insert up to 500 items. However, using Promises.all, both methods would take less than 1.5 seconds (on my machine) to insert 500 items.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;dynamoDB&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nx"&gt;AWS&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;DynamoDB&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;listOfMovies&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nx"&gt;uploadBatchWithPartiQL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;listOfMovies&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;statements&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;listOfMovies&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;movie&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;item&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;movie&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Statement&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;`INSERT INTO Movies VALUE &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;item&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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;let&lt;/span&gt; &lt;span class="nx"&gt;promises&lt;/span&gt; &lt;span class="o"&gt;=&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;statements&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="mi"&gt;25&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;upperLimit&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Math&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;min&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="mi"&gt;25&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;statements&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="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;batch&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;statements&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;slice&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="nx"&gt;upperLimit&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nx"&gt;promises&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;dynamoDB&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;batchExecuteStatement&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;Statements&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;batch&lt;/span&gt;
          &lt;span class="p"&gt;}).&lt;/span&gt;&lt;span class="nx"&gt;promise&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="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;all&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;promises&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;batchCall&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;batchCall&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;listOfMovies&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;createFakeMovies&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;500&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nx"&gt;uploadBatchWithPartiQL&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;listOfMovies&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Conclusion and should you use PartiQL?
&lt;/h3&gt;

&lt;p&gt;It's up to your comfort level of what you would like to use to decide if you want to include PartiQL in your codebase. There is no performance penalty to use either option. AWS provided PartiQL because AWS naturally likes to provide more than a way to communicate with DynamoDb. They also wanted to provide a tool that provides familiar semantics to access the data.&lt;/p&gt;

&lt;p&gt;PartiQL seems to have a slight advantage in batch operations compared to batchWrite from the Document Client, particularly the ability to do batch updates. So if you are extensively working with batch operations, it might be worth looking into if PartiQL will improve your work case.&lt;/p&gt;

&lt;p&gt;One question you might have is whether using PartiQL is a good idea with Javascript. I went over the importance of differentiating between single quotes and double quotes, which in JS can be tricky to manage. To manage that for the examples above, I've shown that I had to implement a custom stringifier method to create correct partiQL statements. My answer would be "it depends" whether the appeal of writing your queries in SQL-like format is more than using the Document Client, which is also a great way to run operations on DynamoDb items.&lt;/p&gt;

&lt;p&gt;When writing this, the AWS Dynamodb PartiQL &lt;a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/ql-reference.html"&gt;documentation&lt;/a&gt; only list examples written in Java and AWS CLI. As this is a new feature released, I'm sure AWS will add more support, and maybe the open-source community will add a useful util tool to make Javascript types compatible with partiQL statements.&lt;/p&gt;

&lt;h6&gt;
  
  
  Further Resources
&lt;/h6&gt;

&lt;p&gt;Do you like working with DynamoDb and want to learn more? Here are some resources I recommend.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;DynamoDb DocumentClient &lt;a href="https://github.com/dabit3/dynamodb-documentclient-cheat-sheet"&gt;cheat sheet&lt;/a&gt; by Nader Dabit.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.dynamodbbook.com/"&gt;The DynamoDb Book&lt;/a&gt; by Alex DeBrie.&lt;/li&gt;
&lt;li&gt;Useful tools to make working with DynamoDb easier:

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/workbench.html"&gt;NoSQL Workbench for DynamoDB&lt;/a&gt;:  A free client-side GUI application.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://dynobase.dev/"&gt;Dynobase&lt;/a&gt;: Professional GUI Client for DynamoDB (paid).&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I hope you enjoyed this article and learned a thing or two about DynamoDb. Let me know in the comments below or on &lt;a href="https://twitter.com/abbadev"&gt;Twitter&lt;/a&gt; of any questions you might have.&lt;/p&gt;

</description>
      <category>aws</category>
      <category>dynamodb</category>
      <category>partiql</category>
      <category>javascript</category>
    </item>
    <item>
      <title>Add comments to your blog using GitHub Issues</title>
      <dc:creator>Abdulla T</dc:creator>
      <pubDate>Fri, 18 Sep 2020 17:02:34 +0000</pubDate>
      <link>https://forem.com/abbadev/add-comments-to-your-blog-using-github-issues-531</link>
      <guid>https://forem.com/abbadev/add-comments-to-your-blog-using-github-issues-531</guid>
      <description>&lt;p&gt;Having comments on your personal blogs can help you interact with your readers, and make them feel heard too. They can make your blog posts feel alive, rather than just a one-way interaction.&lt;/p&gt;

&lt;p&gt;Of course, having comments in your blog may have some downsides, such as spammy and offensive comments from some trolls. Therefore, it is not advisable to have a very open comment system without a user login feature to deter trolls and bots.&lt;/p&gt;

&lt;p&gt;I've seen some people use Disqus, which has a few pros and cons (such as ads or price), and I've also seen some developers build their own firebase-based solutions. However, I wanted to have something simple and free that would also look nice.&lt;/p&gt;

&lt;p&gt;I read about &lt;a href="https://utteranc.es/"&gt;Utterances&lt;/a&gt; from a blog post by Tania Rascia, who has a brilliant blog that I highly recommend, and I was quite impressed with how easy it is to implement it in my newly built site quickly. It took me a total of 20 minutes to integrate it with my Gatsby blog, so I'll be explaining in this article the steps to follow so you can also add it to your blog easily.&lt;/p&gt;

&lt;h3&gt;
  
  
  What is Utterances?
&lt;/h3&gt;

&lt;p&gt;It's a free open source app, that will work as a widget in your blog using GitHub issues as the blog comments storage.&lt;/p&gt;

&lt;p&gt;It will create a new issue for new posts and put any comments on your posts as comments on that issue itself. You can edit your comment from that GitHub issue too. It's pretty neat.&lt;/p&gt;

&lt;h3&gt;
  
  
  Is Utterances right for my blog?
&lt;/h3&gt;

&lt;p&gt;Since Utterances stores the comments in GitHub issues, this post assumes that your blog is targeting an audience of developers who would generally have a GitHub account.&lt;/p&gt;

&lt;p&gt;Also, if your blog is super popular with high traffic, using this solution might not work for you because the widget might hit the GitHub API rate limit and your comment feature will not work all the time, so keep this in mind for the future.&lt;/p&gt;

&lt;h3&gt;
  
  
  How does it look like?
&lt;/h3&gt;

&lt;p&gt;Just scroll down to the end of the &lt;a href="https://abba.dev/blog/blog-comments-with-utterances"&gt;post on my blog&lt;/a&gt; to try it out. You can view the comments and issues &lt;a href="https://github.com/abbathaw/blog-comments/issues"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Adding Utterances to your blog
&lt;/h3&gt;

&lt;p&gt;Adding Utterances in a standard Html-Js website is a matter of merely adding a simple script. The utterances website documents the easy steps to do this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// example of embedding this in a non-react app&lt;/span&gt;

&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt; &lt;span class="nx"&gt;src&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://utteranc.es/client.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="nx"&gt;repo&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;[ENTER REPO HERE]&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="nx"&gt;issue&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nx"&gt;term&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;pathname&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;comment&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;github-light&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="nx"&gt;crossorigin&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;anonymous&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
        &lt;span class="k"&gt;async&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/script&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;However, this walkthrough will be about adding Utterances in a react based blog, such as Gatsby or Next.&lt;/p&gt;

&lt;p&gt;Here is a summary of the steps to follow:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Setting up the public repository in GitHub.&lt;/li&gt;
&lt;li&gt;Install the utterances GitHub app onto the repo.&lt;/li&gt;
&lt;li&gt;Add a react component for the comment.&lt;/li&gt;
&lt;li&gt;Add a &lt;code&gt;useEffect&lt;/code&gt; in the posts component to render the widget.&lt;/li&gt;
&lt;/ol&gt;

&lt;h4&gt;
  
  
  Step 1: Setting up the public repository in GitHub
&lt;/h4&gt;

&lt;p&gt;You have two options, use an existing repo, or create a new empty repo. Either way, it has to be a public repo. Creating a new repo is better to avoid polluting the issues of your code repo with the comments (though you can add labels to the comments).&lt;/p&gt;

&lt;p&gt;In this comments repository, you can also commit a &lt;code&gt;utterances.json&lt;/code&gt; file and add the domain of your website. This will prevent other unauthorized websites using your comments repo, which can happen if someone clones your website and forgets to change the utterances script (which we will add below in step 4).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="err"&gt;//utterances.json&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;span class="nl"&gt;"origins"&lt;/span&gt;&lt;span class="p"&gt;:&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;span class="s2"&gt;"https://yourDomain.tld"&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;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;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The above file gets committed in the same repository you are using for the comments, not in your blog repository.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Step 2: Install the utterances GitHub app onto the repo
&lt;/h4&gt;

&lt;p&gt;After you have decided which repo you will use, we can go to the &lt;a href="https://github.com/apps/utterances"&gt;utterances GitHub app&lt;/a&gt; to install it on our repository.&lt;br&gt;
Just give the app the necessary permissions to read and write to the selected repository only, and we can move on to step 3.&lt;/p&gt;
&lt;h4&gt;
  
  
  Step 3: Create a react component for the comments container
&lt;/h4&gt;

&lt;p&gt;Now, that we have everything ready, let's create a new component in our blog that we can then use wherever we want to integrate our comments.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;//components/Comment.js&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;Comment&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;forwardRef&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;props&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;commentBox&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;div&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;commentBox&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="nx"&gt;className&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;comments&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="o"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;Comment&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;So, we are simply creating an empty div here but what matters is that we are forwarding the reference &lt;code&gt;ref={commentBox}&lt;/code&gt; to this div. React &lt;a href="https://reactjs.org/docs/forwarding-refs.html#forwarding-refs-to-dom-components"&gt;forwarding refs&lt;/a&gt; allow us to obtain a ref to the &lt;code&gt;div&lt;/code&gt; DOM element, which we will use in the step below.&lt;/p&gt;

&lt;h4&gt;
  
  
  Step 4: Use the Comments component in our posts template
&lt;/h4&gt;

&lt;p&gt;In this last step, we will need to integrate the &lt;code&gt;Comment&lt;/code&gt; component in the place where we want the comments to show. In this example, we will use it in the Post Footer Component. You can directly use it in the post-template file, or anywhere you want.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;In a rush:&lt;/strong&gt; Jump to the end for the final code of this step.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;Let's create a ref first in our parent component &lt;code&gt;PostFooter.js&lt;/code&gt;.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="c1"&gt;// PostFooter.js&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;PostFooter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;commentBox&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createRef&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="c1"&gt;// ...&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;PostFooter&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;After that, we will be adding a &lt;code&gt;useEffect&lt;/code&gt; to create the script element on component mount. I've added some comments to explain the value for each attribute.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;commentScript&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;script&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="nx"&gt;commentScript&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
  &lt;span class="nx"&gt;commentScript&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://utteranc.es/client.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

  &lt;span class="c1"&gt;// define the name of the repository you created here as 'owner/repo'&lt;/span&gt;
  &lt;span class="c1"&gt;// or import it from your config file if you have one.&lt;/span&gt;
  &lt;span class="nx"&gt;commentScript&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;repo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;siteConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;commentsRepo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;// define the blog post -&amp;gt; issue mapping (e.g. page pathname, page url).&lt;/span&gt;
  &lt;span class="c1"&gt;// here the issues will be created with the page pathname as the issue title.&lt;/span&gt;
  &lt;span class="nx"&gt;commentScript&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;issue-term&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="s1"&gt;pathname&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;// define a custom label that you want added to your posts.&lt;/span&gt;
  &lt;span class="nx"&gt;commentScript&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;label&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="s1"&gt;blog-comment&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;// define if you want to use dark or light theme.&lt;/span&gt;
  &lt;span class="nx"&gt;commentScript&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;theme&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="s1"&gt;github-light&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="nx"&gt;commentScript&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;crossorigin&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="s1"&gt;anonymous&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

  &lt;span class="c1"&gt;// we will append this script as a child to the ref element we have created above&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;commentBox&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;commentBox&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;commentBox&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;commentScript&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&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="s2"&gt;`Error adding utterances comments on: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;commentBox&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&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;span class="p"&gt;[])&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;If you have a dark/light theme toggler in your blog,  you can still modify this further to allow changing the theme based on your user preference. Let's bring in the theme context which should be implemented somewhere else in your site (I won't go in much detail now on how to implement the theme context, as it's not relevant to this post).
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;theme&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useThemeContext&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;commentsTheme&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;theme&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;theme&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dark&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="s1"&gt;github-dark&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="s1"&gt;github-light&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;

    &lt;span class="nx"&gt;commentScript&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;theme&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;commentsTheme&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

   &lt;span class="c1"&gt;// ...&lt;/span&gt;

 &lt;span class="p"&gt;},&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Notice that we added theme as the second argument to the useEffect function. This allows triggering the useEffect function every time the user toggles the theme.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;However, there is a catch, as we still need to implement a cleanup on this useEffect(); otherwise, we will end up with multiple comment boxes every time the theme is toggled. To clean up, we need to return a function in the useEffect function, and in that function, we can simply remove the utterances elements from the dom.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;
  &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;

  &lt;span class="c1"&gt;// ...&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;removeScript&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
       &lt;span class="nx"&gt;commentScript&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
       &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;.utterances&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
   &lt;span class="p"&gt;};&lt;/span&gt;

  &lt;span class="c1"&gt;// clean up on component unmount&lt;/span&gt;
   &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
     &lt;span class="nx"&gt;removeScript&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;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;Finally, the last step is to render the &lt;code&gt;Comment&lt;/code&gt; component we created in step 3 and pass it the &lt;code&gt;commentBox&lt;/code&gt; ref.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;    &lt;span class="p"&gt;...&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
          &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Comment&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;commentBox&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;        &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;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;Now you can use the PostFooter component in your post-template or on your page directly.&lt;/p&gt;

&lt;h5&gt;
  
  
  Final code for step 4
&lt;/h5&gt;

&lt;p&gt;Here is the final cleaned up code for the &lt;code&gt;PostFooter.js&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;
&lt;span class="c1"&gt;// PostFooter.js&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;react&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="nx"&gt;Comment&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;./components/Comment&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;useThemeContext&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../context/theme-context&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;siteConfig&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;../utils/site-config&lt;/span&gt;&lt;span class="dl"&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;PostFooter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;commentBox&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;React&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createRef&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;theme&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;useThemeContext&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

  &lt;span class="nx"&gt;useEffect&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;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;commentScript&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;script&lt;/span&gt;&lt;span class="dl"&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;commentsTheme&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;theme&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;theme&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;dark&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="s1"&gt;github-dark&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="s1"&gt;github-light&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="nx"&gt;commentScript&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;
    &lt;span class="nx"&gt;commentScript&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;src&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;https://utteranc.es/client.js&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="nx"&gt;commentScript&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;repo&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;siteConfig&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;commentsRepo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;commentScript&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;issue-term&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="s1"&gt;pathname&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;commentScript&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;id&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="s1"&gt;utterances&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;commentScript&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;label&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="s1"&gt;comment&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;commentScript&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;theme&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;commentsTheme&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nx"&gt;commentScript&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;setAttribute&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;crossorigin&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="s1"&gt;anonymous&lt;/span&gt;&lt;span class="dl"&gt;'&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;commentBox&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;commentBox&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;commentBox&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;current&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;appendChild&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;commentScript&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&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="s2"&gt;`Error adding utterances comments on: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;commentBox&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&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;removeScript&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;commentScript&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
      &lt;span class="nb"&gt;document&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;querySelectorAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;.utterances&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;forEach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;el&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;el&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;remove&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
    &lt;span class="p"&gt;};&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nx"&gt;removeScript&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;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;theme&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;

  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="o"&gt;&amp;lt;&amp;gt;&lt;/span&gt;
      &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;Comment&lt;/span&gt; &lt;span class="nx"&gt;ref&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="nx"&gt;commentBox&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;    &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;  &lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;default&lt;/span&gt; &lt;span class="nx"&gt;PostFooter&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;With that implemented, you should now have a commenting feature integrated within your blog. This should be all.&lt;/p&gt;

&lt;p&gt;Thank you for reading. I hope you found this post useful.&lt;/p&gt;




&lt;p&gt;photo credit: &lt;br&gt;
circle icons PNG Designed By flat**** from &lt;a href="https://pngtree.com/"&gt;Pngtree.com&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Like what you read? I just started my new blog (finally) at &lt;a href="https://abba.dev"&gt;abba.dev&lt;/a&gt;. Head over there to join my &lt;a href="https://abba.dev/newsletter"&gt;newsletter&lt;/a&gt; or follow me on &lt;a href="https://twitter.com/abbadev"&gt;twitter&lt;/a&gt; to stay updated with new stuff that I write about as a full-stack software developer. You can expect a lot more posts in JS, nodeJs, AWS, system design and probably much more.&lt;/p&gt;

</description>
      <category>utterances</category>
      <category>comments</category>
      <category>react</category>
      <category>gatsby</category>
    </item>
  </channel>
</rss>
