<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Prasad Saya</title>
    <description>The latest articles on DEV Community by Prasad Saya (@prsaya).</description>
    <link>https://dev.to/prsaya</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%2F948966%2F0b44147b-c910-47aa-88fe-356eb2adc3d2.png</url>
      <title>DEV Community: Prasad Saya</title>
      <link>https://dev.to/prsaya</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/prsaya"/>
    <language>en</language>
    <item>
      <title>Indexes in MySQL – Notes</title>
      <dc:creator>Prasad Saya</dc:creator>
      <pubDate>Mon, 27 Nov 2023 11:48:56 +0000</pubDate>
      <link>https://dev.to/prsaya/indexes-in-mysql-notes-1pbb</link>
      <guid>https://dev.to/prsaya/indexes-in-mysql-notes-1pbb</guid>
      <description>&lt;p&gt;Indexes are used to find rows in a database fast. Without indexes the database has to start from first row and find the required rows until the last row, sequentially (a.k.a. full table scan). Full table scans are slow on tables with large number of rows.&lt;/p&gt;

&lt;p&gt;MySQL uses the indexes to point to the rows as specified in the query criteria and retrieve them quickly. In MySQL you can create different types of indexes based upon your query, search and performance requirement.&lt;/p&gt;

&lt;p&gt;Here is some info about types of indexes, associated commands and index usage by queries.&lt;/p&gt;




&lt;h2&gt;
  
  
  Index Types
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Column index - An index on a single column.&lt;/li&gt;
&lt;li&gt;Composite index - An index on multiple columns. A.k.a. multi-column index, concatenated index.&lt;/li&gt;
&lt;li&gt;Unique index - An index on column(s) that have no duplicate values.&lt;/li&gt;
&lt;li&gt;Primary key index - A special index that stores row data for InnoDB tables. If a primary key is not defined, the first Unique index is used for this. Otherwise, a hidden index is created on a synthetic column of row id values. A.k.a. Clustered index.&lt;/li&gt;
&lt;li&gt;Secondary index - A non-primary key index.&lt;/li&gt;
&lt;li&gt;Covering index - An index that includes all the columns retrieved by a query. Instead of using the index values as pointers to find the full table rows, the query returns values from the index structure, thus saving disk I/O.&lt;/li&gt;
&lt;li&gt;Partial index - An index that represents only part of a column value, typically the first N characters of a long VARCHAR value.&lt;/li&gt;
&lt;li&gt;Spatial index - An index created on spatial data type (e.g., POINT and GEOMETRY) columns. Spatial data is also known as geographic data or geospatial data. You can also create non-spatial indexes on spatial data types.&lt;/li&gt;
&lt;li&gt;Fulltext index - An index that holds the search index in the MySQL full-text search mechanism. This is for text-based data types (CHAR, VARCHAR, or TEXT).&lt;/li&gt;
&lt;li&gt;Hash index - A type of index intended for queries that use equality operators, rather than range operators such as greater-than or BETWEEN. It is available for MEMORY tables.&lt;/li&gt;
&lt;li&gt;Adaptive hash index - An optimization for InnoDB tables that can speed up lookups using = and IN operators, by constructing a hash index in memory.&lt;/li&gt;
&lt;li&gt;Descending index - An index where index storage is optimized to process ORDER BY column DESC clauses.&lt;/li&gt;
&lt;li&gt;Invisible index - An index that is not used by the optimizer. Invisible index makes it possible to test the effect of removing an index on query performance without dropping it.&lt;/li&gt;
&lt;li&gt;Virtual index - An index on virtual or stored generated columns or a combination of regular and generated columns.&lt;/li&gt;
&lt;li&gt;Multi-Valued index - An index defined on a JSON column that stores an array of values.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Creating Indexes
&lt;/h2&gt;

&lt;p&gt;You can create an index, modify, delete or query the database to see what indexes are there. &lt;/p&gt;

&lt;p&gt;Here are some commands and their usage:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create using CREATE TABLE INDEX, ALTER TABLE ADD INDEX, CREATE INDEX&lt;/li&gt;
&lt;li&gt;Modify using ALTER TABLE ALTER INDEX, ALTER TABLE RENAME INDEX&lt;/li&gt;
&lt;li&gt;Delete using ALTER TABLE DROP INDEX, DROP INDEX&lt;/li&gt;
&lt;li&gt;List indexes using SHOW INDEXES&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Example Usage:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;-- Create a table and an index on two columns c1 and c2
CREATE TABLE t1 (
  c1 VARCHAR(10),
  c2 VARCHAR(15),
  c3 VARCHAR(30),
  c4 DATETIME,
  INDEX ix1 (c1, c2)
);

-- Add a unique index
ALTER TABLE t1 ADD UNIQUE INDEX uix1 (c4);

-- List the indexes
SHOW INDEXES FROM t1\G

-- Create a partial index
CREATE INDEX part_of_c3 ON t1 (c3(10));

-- Add a JSON data column to the table
-- Create an index on its name field (NOTE: your collation may be different value)
ALTER TABLE t1 ADD COLUMN jdata JSON;
DESCRIBE t1;
CREATE INDEX jdata_name ON t1 ((CAST(jdata-&amp;gt;&amp;gt;"$.name" AS CHAR(20)) COLLATE cp850_general_ci));

-- Delete an index (following two statements has same result)
ALTER TABLE t1 DROP INDEX uix1;
DROP INDEX uix1 ON t1;

SHOW INDEXES FROM t1;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Verifying Index Usage
&lt;/h2&gt;

&lt;p&gt;You can check whether your queries really use the indexes created in the tables. For this, use the EXPLAIN statement. EXPLAIN provides information from the optimizer about how MySQL would execute a query. With the help of EXPLAIN, you can see where you should add indexes to tables so that the statement executes faster by using indexes to find rows.&lt;/p&gt;

&lt;p&gt;EXPLAIN works with SELECT, DELETE, INSERT, REPLACE, and UPDATE statements. Here is an example using SELECT on this table &lt;code&gt;test2&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;CREATE TABLE test2 (
  c1 int NOT NULL,
  c2 varchar(10),
  PRIMARY KEY (c1)
);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sample rows in table:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mysql&amp;gt; SELECT * FROM test2;
+-----+---------+
| c1  | c2      |
+-----+---------+
|   1 | NULL    |
|   5 | five    |
|   4 | four    |
|   3 | three   |
|   2 | two     |
...
+-----+---------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;List the table indexes and check the usage in a SELECT query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mysql&amp;gt; SHOW INDEX IN test2\G
*************************** 1. row ***************************
        Table: test2
   Non_unique: 0
     Key_name: PRIMARY
  Column_name: c1
...


mysql&amp;gt; EXPLAIN SELECT * FROM test2 WHERE c1 &amp;gt;= 3\G
*************************** 1. row ***************************
           id: 1
  select_type: SIMPLE
        table: test2
   partitions: NULL
         type: range
possible_keys: PRIMARY
          key: PRIMARY
...

mysql&amp;gt; EXPLAIN ANALYZE SELECT * test2 WHERE c1 &amp;gt;= 3\G
*************************** 1. row ***************************
EXPLAIN: -&amp;gt; Filter: (test2.c1 &amp;gt;= 3)  (cost=1.46 rows=6) (actual time=0.016..0.0251 rows=6 loops=1)
    -&amp;gt; Index range scan on test2 using PRIMARY over (3 &amp;lt;= c1)  (cost=1.46 rows=6) (actual time=0.0143..0.0224 rows=6 loops=1)

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

&lt;/div&gt;



&lt;p&gt;EXPLAIN ANALYZE (introduced in MySQL 8.0.18) runs a statement and produces EXPLAIN output along with timing and additional information about how the optimizer's expectations matched the actual execution.&lt;/p&gt;




&lt;h2&gt;
  
  
  Useful Notes
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Index prefix - The initial or leading columns of a composite index. A query that references the first few columns of a composite index can use the index, even if the query does not reference all the columns in the index.&lt;/li&gt;
&lt;li&gt;Index hints - Index hints give the optimizer information about how to choose indexes during query processing (for overriding the indexes recommended by the optimizer). Index hints apply to SELECT, UPDATE and DELETE statements.&lt;/li&gt;
&lt;li&gt;Index extensions - InnoDB automatically extends each secondary index by appending the primary key columns to it. If a table has a column c1 as primary key and column c2 has an index, MySQL (optimizer) treats the index on c2 as c2+c1 columns.&lt;/li&gt;
&lt;li&gt;Full table scan - A query that requires reading the entire contents of a table, rather than just selected portions using an index.&lt;/li&gt;
&lt;li&gt;Optimizer - The MySQL component that determines the best indexes and join order to use for a query, based on characteristics and data distribution of the relevant tables. A.k.a. Query Optimizer.&lt;/li&gt;
&lt;li&gt;Index data structures - Most MySQL indexes (PRIMARY KEY, UNIQUE, INDEX, and FULLTEXT) are stored in B-trees. Some exceptions are (a) indexes on spatial data types use R-trees, (b) MEMORY tables use hash indexes by default, and (c) InnoDB uses inverted lists for FULLTEXT indexes.&lt;/li&gt;
&lt;li&gt;MySQL storage engines - Storage engines are MySQL components that handle the SQL operations for different table types. InnoDB is the default and most general-purpose storage engine. There are also MyISAM, MEMORY, CSV, NDB, and others. Each of these have their specific purpose. Some indexes are specific to some storage engines.&lt;/li&gt;
&lt;/ul&gt;




&lt;p&gt;You can install MySQL Server on your computer by following the instructions from this GitHub Gist &lt;a href="https://gist.github.com/prsaya/1755f873071a12ef246c89e245e67bb5"&gt;Basic steps to install MySQL 8 Server and create database data&lt;/a&gt; and try the above code snippets. &lt;/p&gt;

&lt;p&gt;For further reference see &lt;a href="https://dev.mysql.com/doc/refman/8.0/en/"&gt;MySQL 8.0 Reference Manual&lt;/a&gt;.&lt;/p&gt;







</description>
      <category>mysql</category>
      <category>database</category>
    </item>
    <item>
      <title>Revisiting Photography after a long (, long...) time</title>
      <dc:creator>Prasad Saya</dc:creator>
      <pubDate>Wed, 22 Nov 2023 14:30:15 +0000</pubDate>
      <link>https://dev.to/prsaya/revisiting-photography-after-a-long-long-time-465p</link>
      <guid>https://dev.to/prsaya/revisiting-photography-after-a-long-long-time-465p</guid>
      <description>&lt;p&gt;Couple of months back I had ideas about shooting some photos for fun and hobby. Hence, I started looking for information about the current state of photography.&lt;/p&gt;

&lt;p&gt;I occasionally use my Android phone camera, but that is still a phone for me. A camera means you have reason to take time off or go out and do something more purposeful - photography. For me photography was (still is) technique and involving light, colors, things, nature, people, aperture, ISO, shutter speed, and exposure. Being out on your own sometimes at odd times, odd places and a satisfaction (somewhat akin to that of being on a golf course driving range on your own practicing)  irrespective of the outcome.&lt;/p&gt;

&lt;p&gt;I learnt photography long time back when I was in college, around year 1980. I was studying my Mechanical Engineering degree and I had enrolled into the college photography club. Naturally, I came to know experts in the field and I was interested. &lt;/p&gt;

&lt;p&gt;I learnt by reading photography books, trying, taking help, and doing together with a friend. I had a camera (a rangefinder camera with built in light meter) and some borrowed equipment (a tripod, and a TLR camera). Armed with these and some trying I was able to get the best photographer prize at the annual college competition in 1982. My photos were mostly black &amp;amp; white, shot in the dark, and not the usual sceneries, sunsets, flowers, etc. I had enjoyed the action and learnt the basics well. It is not easy compared to today’s equipment and their capabilities.&lt;/p&gt;

&lt;p&gt;After that I did some photography once in a while. Back in year 2001 got my own Nikon SLR camera with a 24-120mm zoom lens. That was still using photographic film, not the digital photography. The interest did not last long.&lt;/p&gt;




&lt;blockquote&gt;
&lt;p&gt;The title picture is a selfie in a mirror. It was one of first photos I shot with my recent and new camera.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Camera
&lt;/h2&gt;

&lt;p&gt;Couple of months back, I started noting the digital cameras and their capabilities. After few weeks, I knew that photography technique and basics are mostly the same, but it’s the equipment, technologies, convenience, etc., are different.&lt;/p&gt;

&lt;p&gt;I did get a book to revisit my knowledge about photography. The book is "Understanding Exposure" fourth edition, by Bryan Peterson. The book is about photography and technique (irrespective of equipment). It suited me well and I liked it, as it had the right knowledge I needed to relearn.&lt;/p&gt;

&lt;p&gt;I also avoided any books and knowledge involving equipment about digital photography. I felt that a distraction and excitement. Though I browsed a few online videos for relevant information.&lt;/p&gt;

&lt;p&gt;Once I was convinced that this is something I need to try, I looked for a camera with changeable lenses - a SLR or nowadays a DSLR. It needed to be a beginner level, and also interesting to me. &lt;/p&gt;

&lt;p&gt;I found this camera - Nikon ZFC. It is a mirrorless DSLR (mirrorless DSLRs are light weight, smaller and newer tech). It can capture 21 Mega pixel digital photos. I opted for a normal 50mm f1.8 lens to go with it. It can also shoot decent videos. I got this couple of weeks back. And, a tripod earlier this week.&lt;/p&gt;

&lt;p&gt;Initially, the new camera was a bit overwhelming. It had a user manual of 600+ pages. An array of displays, menus, submenus, settings, technology and more terminology. My camera also had manual controls for ISO, shutter speed and exposure compensation like in older film cameras giving it a unique and retro look (which I like).&lt;/p&gt;

&lt;p&gt;I have to learn this new technology of digital photography. I know there is a good learning curve. I am learning by myself.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv0wnv8yp9w1159tzbvxc.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fv0wnv8yp9w1159tzbvxc.jpg" alt="Picture of my Nikon ZFC Camera"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Initial try
&lt;/h2&gt;

&lt;p&gt;Back in January 2023, I had written a post on this site &lt;a href="https://dev.to/prsaya/books-i-had-read-in-the-past-decade-or-so-5d26"&gt;Books I had read in the past decade or so...&lt;/a&gt;. I needed a picture with books to go with the article’s title. It was a borrowed one. I wanted to replace that photo with a real one and with the real books I had listed in the article. So, I started to get a decent picture using the new camera. I tried various shots and finally got the photo and updated on the post.&lt;/p&gt;

&lt;p&gt;It was not easy with my new equipment. I used my study lamps for lighting. Tried various positions, settings on the camera and lighting. After a few photos I settled for one. This was little exciting too. I did not know which was the best picture of the few. The urge to post it online immediately was there.&lt;/p&gt;

&lt;p&gt;So, on November 13th I edited the article to have the new picture. It was satisfying. The experience was good and encouraging.&lt;/p&gt;

&lt;p&gt;The photo from initial shooting:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl37i9fn33x92gv3y4fui.JPG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl37i9fn33x92gv3y4fui.JPG" alt="Picture of a stack of books"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This one is from a tree as shot from my bedroom window (I wanted to make the background out of focus from the target):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpcunzojxbzol989q2fkx.JPG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fpcunzojxbzol989q2fkx.JPG" alt="Picture of a bunch of leaves with blurred background"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  It is not about equipment
&lt;/h2&gt;

&lt;p&gt;Few weeks back I was in my kitchen putting together my breakfast. Fresh fruit is part of my diet. I get Papayas often and they are available plenty. As I cut this one, I noted a familiar shape. This was unexpected. This from the nature. &lt;/p&gt;

&lt;p&gt;Here is a shot with my Android phone.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1td91yjsdq5lic047fg1.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1td91yjsdq5lic047fg1.jpg" alt="Picture of papaya cut half has a heart shaped section"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  What next?
&lt;/h2&gt;

&lt;p&gt;The weather had been cloudy and it’s been raining often lately. This is making it difficult to get out and try the camera outdoors. So is the city traffic. I am waiting to find time and opportunities to get out and experience the photography.&lt;/p&gt;




</description>
      <category>photography</category>
      <category>photos</category>
      <category>hobby</category>
    </item>
    <item>
      <title>Access MySQL Document Store from NodeJS Application</title>
      <dc:creator>Prasad Saya</dc:creator>
      <pubDate>Tue, 19 Sep 2023 08:59:29 +0000</pubDate>
      <link>https://dev.to/prsaya/access-mysql-document-store-from-nodejs-application-b4k</link>
      <guid>https://dev.to/prsaya/access-mysql-document-store-from-nodejs-application-b4k</guid>
      <description>&lt;p&gt;In my previous post &lt;a href="https://dev.to/prsaya/using-mysql-as-a-nosql-document-store-introduction-125p"&gt;Using MySQL as a NoSQL Document Store - Introduction&lt;/a&gt; I had shown accessing MySQL Document Store using the MySQL Shell client using X DevAPI. Please refer the post for an introduction to the JSON data document store, usage of the APIs and the MySQL Shell.&lt;/p&gt;

&lt;p&gt;In this post, I use the &lt;strong&gt;MySQL Connector/Node.js&lt;/strong&gt; (NodeJS Driver) and the X DevAPI APIs in a NodeJS and ExpressJS JavaScript server-side program.&lt;/p&gt;

&lt;p&gt;I had used MySQL Server v8.0.34 and NodeJS v18.17.1 for programming on a Windows 11 computer. The NodeJS application has the following dependencies (from the package.json):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;"dependencies": {
    "@mysql/xdevapi": "8.0.33",
    "express": "^4.18.2"
 }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;npm&lt;/code&gt; registry for the MySQL NodeJS Driver: &lt;a href="https://www.npmjs.com/package/@mysql/xdevapi"&gt;@mysql/xdevapi&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  The Data
&lt;/h2&gt;

&lt;p&gt;I used the following structure for the &lt;strong&gt;JSON document&lt;/strong&gt; data to store in the database. The &lt;strong&gt;database&lt;/strong&gt; (schema) is called &lt;code&gt;X_db&lt;/code&gt; and the &lt;strong&gt;collection&lt;/strong&gt; is &lt;code&gt;users&lt;/code&gt;. I am assuming these already exist. The following is the structure of each document in the collection. Note that the structure can be different for each document in a collection.&lt;/p&gt;

&lt;p&gt;Please refer my previous post (linked at the top) for details about collection, document, the &lt;code&gt;_id&lt;/code&gt; field, creating the collection and the schema.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;{
    "_id": "1",
    "name": "Pete",
    "age": 13,
    "city": "Dallas",
    "favs": [
        "Cheese cake",
        "Skiing"
    ]
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this app we will make sure the &lt;code&gt;name&lt;/code&gt; field is mandatory and is also unique within the &lt;code&gt;users&lt;/code&gt; collection. This is by defining an &lt;strong&gt;index&lt;/strong&gt; on the &lt;code&gt;name&lt;/code&gt; field with &lt;em&gt;unique&lt;/em&gt; and &lt;em&gt;required&lt;/em&gt; &lt;strong&gt;constraints&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;Start the MySQL Shell and connect to the database server. From the MySQL Shell in the default JavaScript mode:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Create a unique and required index on the name field
mysql-js&amp;gt; db.users.createIndex("name", { fields: [ { field: "$.name", type: "text(20)", required: true } ], unique: true })
// List the indexes on the collection
mysql-js&amp;gt; session.sql("SHOW INDEX FROM x_db.users")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In case you need to drop an index, use the following syntax:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mysql-js&amp;gt; db.collection_name.dropIndex("index_name")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  The App
&lt;/h2&gt;

&lt;p&gt;The NodeJS app has two programs - &lt;code&gt;index.js&lt;/code&gt; and &lt;code&gt;database.js&lt;/code&gt;. The &lt;code&gt;database.js&lt;/code&gt; has the database connection code using the MySQL NodeJS Driver APIs. The &lt;code&gt;index.js&lt;/code&gt; is the ExpressJS web server and has the web API routes to perform CRUD (Create, Read, Update and Delete) operations on the MySQL Document Store.&lt;/p&gt;

&lt;p&gt;The app is a barebones program with basic error handling (the data validation and detailed logging is not included for the sake of brevity). The app will show proper responses and logging in case of database connection errors, non existing schema or the collection, data errors for unique and required field constraint violations.&lt;/p&gt;

&lt;p&gt;I have tried the web APIs using Postman software.&lt;/p&gt;

&lt;p&gt;The APIs are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Post request with a JSON document as body to create a user: &lt;code&gt;http://localhost:3000/users/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Get request to list all users sorted by &lt;code&gt;name&lt;/code&gt; field: &lt;code&gt;http://localhost:3000/users/&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Get request to read data for a specified name: &lt;code&gt;http://localhost:3000/users/:name&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Put request to modify the document by its &lt;code&gt;_id&lt;/code&gt; field with the body as a JSON: &lt;code&gt;http://localhost:3000/users/:id&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Delete request to delete a document by its &lt;code&gt;_id&lt;/code&gt;: &lt;code&gt;http://localhost:3000/users/:id&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Code
&lt;/h2&gt;




&lt;h3&gt;
  
  
  database.js:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const mysqlx = require('@mysql/xdevapi')
const config = { host: 'localhost', port: 33060, user: 'user_name', password: 'password' }
const objects = { schema: 'x_db', collection: 'users' }

const getDbSession = async () =&amp;gt; mysqlx.getSession(config)

const getCollection = async () =&amp;gt; {
    const session = await getDbSession()
    const schema = session.getSchema(objects.schema)
    if (! await schema.existsInDatabase()) {
        throw new Error(`The schema ${objects.schema} doesn't exist`)
    }
    return schema.getCollection(objects.collection)
}

module.exports = { getDbSession, getCollection }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  index.js:
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const express = require('express')
const app = express()
const PORT = 3000
const db = require('./database.js')
app.use(express.json())

app.get('/dbinfo', async (req, res, next) =&amp;gt; {
    try {
        const session = await db.getDbSession()
        res.send(session.inspect())
    }
    catch(err) {
        next(err)
    }
})

app.post('/users', async (req, res, next) =&amp;gt; {
    try {
        const collection = await db.getCollection()
        const r = await collection.add(req.body).execute()
        res.send(`Inserted a document with id ${r.getGeneratedIds()}`)
    }
    catch(err) {
        next(err)
    }
})

app.get('/users/:name', async (req, res, next) =&amp;gt; {
    try {
        const collection = await db.getCollection()
        const crsr = await collection.find('name = :param')
                                        .fields(['_id', 'name', 'city'])
                                        .bind('param', req.params.name)
                                        .execute()
        res.send(crsr.fetchAll())
    }
    catch(err) {
        next(err)
    }
})

app.get('/users', async (req, res, next) =&amp;gt; {
    try {
        const collection = await db.getCollection()
        const crsr = await collection.find().sort("name asc").execute()
        res.send(crsr.fetchAll())
    }
    catch(err) {
        next(err)
    }
})

app.put('/users/:id', async (req, res, next) =&amp;gt; {
    const key = Object.keys(req.body)[0]
    try {
        const collection = await db.getCollection()
        const r = await collection.modify('_id = :param')
                                    .set(key, req.body[key])
                                    .bind('param', req.params.id)
                                    .execute()
        res.send(`Updated ${r.getAffectedItemsCount()} document`)
    }
    catch(err) {
        next(err)
    }
})

app.delete('/users/:id', async (req, res, next) =&amp;gt; {
    try {
        const collection = await db.getCollection()
        const r = await collection.remove('_id = :param')
                                    .bind('param', req.params.id)
                                    .execute()
        res.send(`Deleted ${r.getAffectedItemsCount()} document`)
    }
    catch(err) {
        next(err)
    }
})

app.use((err, req, res, next) =&amp;gt; {
    console.log("&amp;lt;&amp;lt;&amp;lt;ERROR&amp;gt;&amp;gt;&amp;gt;")
    console.log(err)
    res.send(err.toString())
})

app.listen(PORT, () =&amp;gt; {
    console.log(`Express app listening on port ${PORT}`)
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.mysql.com/doc/dev/connector-nodejs/latest/"&gt;MySQL Connector/Node.js API and Reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.mysql.com/doc/x-devapi-userguide/en/devapi-users-introduction.html"&gt;MySQL - X DevAPI User Guide&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




</description>
      <category>mysql</category>
      <category>json</category>
      <category>nosql</category>
      <category>node</category>
    </item>
    <item>
      <title>Using MySQL as a NoSQL Document Store - Introduction</title>
      <dc:creator>Prasad Saya</dc:creator>
      <pubDate>Sat, 16 Sep 2023 08:15:16 +0000</pubDate>
      <link>https://dev.to/prsaya/using-mysql-as-a-nosql-document-store-introduction-125p</link>
      <guid>https://dev.to/prsaya/using-mysql-as-a-nosql-document-store-introduction-125p</guid>
      <description>&lt;p&gt;MySQL is mostly known to be SQL database server. To store JSON data it has table columns of &lt;a href="https://dev.mysql.com/doc/refman/8.0/en/json.html"&gt;JSON data type&lt;/a&gt;. In addition, MySQL can be used as a document store and perform "NoSQL" operations. This post is about getting an introduction to this feature.&lt;/p&gt;

&lt;p&gt;Specialized clients can perform SQL as well as CRUD operations on the document database. These clients are &lt;strong&gt;MySQL Shell&lt;/strong&gt; and the &lt;strong&gt;MySQL Connectors&lt;/strong&gt;. MySQL Shell is an interactive interface using JavaScript, Python or SQL modes. Connectors are used for developing applications using programming languages like Java, NodeJS, Python, C++, etc. &lt;/p&gt;

&lt;p&gt;The main components for using MySQL as document store are &lt;strong&gt;X Plugin&lt;/strong&gt;, &lt;strong&gt;X Protocol&lt;/strong&gt; and &lt;strong&gt;X DevAPI&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;X Plugin enables MySQL Server to communicate with these clients. These clients communicate with a MySQL Server using X Protocol. X DevAPI is used to develop client applications.&lt;/p&gt;

&lt;p&gt;In this post we will use MySQL Shell to perform some operations on document store.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;To try the code samples you will require an installation of MySQL Server and MySQL Shell on your computer. I had used MySQL Server and Shell with the version 8.0.34 on a Windows 11 computer.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  MySQL Server
&lt;/h2&gt;

&lt;p&gt;In case you need to install MySQL newly, there are instructions from the GitHub Gist: &lt;a href="https://gist.github.com/prsaya/1755f873071a12ef246c89e245e67bb5"&gt;Basic steps to install MySQL 8 Server and create database data&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Verify X Plugin is installed on the server using the following command from the &lt;code&gt;mysql&lt;/code&gt; client:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mysql&amp;gt; SHOW plugins;
+-------------------+----------+
| Name              | Status   | ...
+-------------------+----------+
...
| mysqlx            | ACTIVE   | ...
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  MySQL Shell
&lt;/h2&gt;

&lt;p&gt;The next step is to install MySQL Shell software.&lt;/p&gt;

&lt;h3&gt;
  
  
  Requirement
&lt;/h3&gt;

&lt;p&gt;Make sure you have the Visual C++ Redistributable for Visual Studio 2015. You can verify if already installed from Windows Control Panel -&amp;gt; Programs and Features.&lt;/p&gt;

&lt;h3&gt;
  
  
  Download and install
&lt;/h3&gt;

&lt;p&gt;Visit the MySQL website and navigate to MySQL Community Downloads -&amp;gt; MySQL Shell&lt;/p&gt;

&lt;h3&gt;
  
  
  Starting and connecting to MySQL Server
&lt;/h3&gt;

&lt;p&gt;Make sure your MySQL Server is started and running. We are using the Windows command prompt. &lt;/p&gt;

&lt;p&gt;From the MySQL Shell install directory:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;command prompt&amp;gt;&amp;gt; bin\mysqlsh
MySQL Shell 8.0.34
...
mysql-js&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By default the shell starts in JS mode.&lt;/p&gt;

&lt;p&gt;Note the MySQL Shell is not connected to the server.  The connection to MySQL Server instance is handled by a &lt;strong&gt;session&lt;/strong&gt; object. &lt;/p&gt;

&lt;p&gt;To see information about the current global session:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mysql-js&amp;gt; shell.status()
MySQL Shell version 8.0.34
Not Connected.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Connect to the server
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mysql-js&amp;gt; \connect mysqlx://user_name@localhost:33060
mysql-js&amp;gt; shell.status()
MySQL Shell version 8.0.34
Connection Id: 28
Server version: 8.0.34 MySQL Community Server - GPL
Current user: user@localhost
Protocol version: X protocol
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;NOTE: You can also start mysqlsh with a session from command prompt:&lt;br&gt;
&lt;code&gt;command prompt&amp;gt;&amp;gt; mysqlsh mysqlx://user_name@localhost:33060&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Exit the MySQL Shell.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mysql-js&amp;gt; \quit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  MySQL Shell Global Objects
&lt;/h3&gt;

&lt;p&gt;MySQL Shell includes a number of built-in global objects that exist in both JavaScript and Python modes. Some useful ones are the &lt;code&gt;session&lt;/code&gt;, &lt;code&gt;db&lt;/code&gt; and &lt;code&gt;shell&lt;/code&gt;. Their usage is shown in this post's code samples.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;db is available when the global session was established using an X Protocol connection with a default database specified, and represents that schema.&lt;/li&gt;
&lt;li&gt;session is available when a global session is established, and represents the global session.&lt;/li&gt;
&lt;li&gt;shell provides access to various MySQL Shell functions.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Document Store
&lt;/h2&gt;

&lt;p&gt;The main concepts are the &lt;strong&gt;JSON Document&lt;/strong&gt;, &lt;strong&gt;Collection&lt;/strong&gt; and &lt;strong&gt;CRUD&lt;/strong&gt; (Create, Read, Update and Delete) operations.&lt;/p&gt;

&lt;p&gt;A JSON document is a data structure composed of key-value pairs. This is the fundamental structure for using MySQL as document store. The document key-value values can be simple data types, such as integers or strings, but can also contain other documents, arrays, and lists of documents. &lt;/p&gt;

&lt;p&gt;A JSON document is represented internally using the MySQL binary JSON object, through the MySQL JSON datatype.&lt;/p&gt;

&lt;p&gt;Note that a document does not need to have a predefined structure. A collection can contain multiple documents with different structures.&lt;/p&gt;

&lt;p&gt;A collection is a container that is used to store JSON documents in a MySQL database. You can perform CRUD operations against a collection of documents.&lt;/p&gt;

&lt;p&gt;Each collection has a unique name and exists within a schema. Schema is equivalent to a database.&lt;/p&gt;




&lt;h2&gt;
  
  
  Collection - create, list and delete
&lt;/h2&gt;

&lt;p&gt;Start MySQL Shell and connect to the server.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mysql-js&amp;gt; db                    /* this returns empty, as no existing schema is specified with the connection */
mysql-js&amp;gt; \use &amp;lt;existing_db&amp;gt;    /* specify a default schema, and it must be an existing schema */

mysql-js&amp;gt; \sql                  /* change the mode to sql */
                                /* check what databases exist, and can create one if needed */
                                /* in SQL mode you can use mysql SQL commands */
SQL&amp;gt; SHOW DATABASES;        -- list databases
+--------------------+
| Database           |
+--------------------+
| information_schema |
| mysql              |
...

SQL&amp;gt; CREATE DATABASE x_db;  -- create a new database
SQL&amp;gt; \js                    -- return to JavaScript mode

mysql-js&amp;gt; \use x_db;                    // make the newly created database as default database
mysql-js&amp;gt; db
Default schema `x_db` accessible through db.

mysql-js&amp;gt; db.getCollections()           // list collections in the default schema
[]
mysql-js&amp;gt; db.createCollection("users")  // create a new collection in the database
&amp;lt;Collection:users&amp;gt;
mysql-js&amp;gt; db.getCollections()
[
    &amp;lt;Collection:users&amp;gt;
]
mysql-js&amp;gt; db.dropCollection("users")    // delete the collection
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  CRUD Operations on the Collection
&lt;/h2&gt;




&lt;h3&gt;
  
  
  CREATE
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mysql-js&amp;gt; db.users.add({ name: "Jerry", age: 10 })  // insert a new document into the collection

mysql-js&amp;gt; db.users.find()                           // list all documents in the collection
{
    "_id": "000065017f9d0000000000000001",
    "age": 10,
    "name": "Jerry"
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;Note the &lt;code&gt;_id&lt;/code&gt; field. The _id field is a mandatory field for each document in the collection. This acts as a primary key. It is (and must be) a unique value within the collection. Its value is set by the server (when not provided) or can be provided. It is immutable (cannot be changed or deleted).&lt;br&gt;
&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mysql-js&amp;gt; db.users.add({ name: "Jill", age: 12 }, { name: "Jim", age: 9 })  // insert two documents
mysql-js&amp;gt; db.users.add({ name: "Jack", age: 8, city: "New York" })          // insert document with different structure
mysql-js&amp;gt; db.users.add({ _id: "myid_99", name: "Jamie", age: 11 })          // insert a document with a provided _id

mysql-js&amp;gt; db.users.count()
5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  READ
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;db.users.find("name = 'Jack'")              // search for specific document(s) using a filter
db.users.find("name LIKE 'Ji%' AND age &amp;lt; 10")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The following operators can be used to specify search conditions: OR (||), AND (&amp;amp;&amp;amp;), XOR, IS, NOT, BETWEEN, IN, LIKE, !=, &amp;lt;&amp;gt;, &amp;gt;, &amp;gt;=, &amp;lt;, &amp;lt;=, &amp;amp;, |, &amp;lt;&amp;lt;, &amp;gt;&amp;gt;, +, -, *, /, ~, and %. &lt;/p&gt;

&lt;p&gt;The syntax for expressions that form a search condition is the same as that of traditional MySQL. Note that you must enclose all expressions in quotes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;db.users.find().fields([ "_id", "name" ])   // project specific field(s) in output

db.users.find().fields([ "_id" ]).limit(1)  // read only one document
db.users.find().sort("age desc")            // read documents sorted by age descending
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  UPDATE
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;db.users.modify("name = 'Jack'").set("city", "Chicago")             // change Jack's city as Chicago
db.users.modify("name = 'Jack'").unset("city")                      // remove the city field for Jack
db.users.modify("true").set("info", { state: "NY", favs: [] })      // update all documents with a new object field

db.users.modify("name = 'Jack'").arrayAppend("$.info.favs", "Red")  // add a value to the array field for Jack
db.users.modify("name = 'Jim'").set("info.city", "LA")              // update an object field
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  DELETE
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;db.users.remove("name = 'Jill'");   // remove documents with a condition
db.users.remove("true").limit(1);   // remove one document
db.users.remove("true");            // remove all documents in collection
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  Other Notable Features
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;You can create indexes on the document field(s).&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;You can define document validation i.e., verify documents against a JSON schema. This enables that all documents in the collection have a certain predefined structure.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;There are operations on the collections which work with one document only. These are &lt;code&gt;getOne&lt;/code&gt;, &lt;code&gt;replaceOne&lt;/code&gt;, &lt;code&gt;addOrReplaceOne&lt;/code&gt; and &lt;code&gt;removeOne&lt;/code&gt;. All these methods take the string &lt;code&gt;_id&lt;/code&gt; value as a parameter. For example, &lt;code&gt;db.users.getOne("myid_99")&lt;/code&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Working with Result Sets
&lt;/h2&gt;

&lt;p&gt;All CRUD operations discussed above return a result set object with various attributes.&lt;/p&gt;

&lt;p&gt;The add, modify and remove operations return a &lt;code&gt;Result&lt;/code&gt; class object. This has details about number of rows affected by the operation, auto generated document IDs, warnings, etc., depending on the operation.&lt;/p&gt;

&lt;p&gt;The find operation returns a &lt;code&gt;DocResult&lt;/code&gt; class object. This is the The fetched data set.&lt;/p&gt;

&lt;p&gt;Using the MySQL Shell in JS mode:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Add a new document, and verify the result object

var r = db.users.add({ name: "John" }).execute()
r.getAffectedItemsCount()   // 1
r.getGeneratedIds()         // [ "000064f987110000000000000004" ]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note the &lt;code&gt;execute&lt;/code&gt; method. This is to be specified when using the JavaScript code in MySQL Shell. In interactive mode this is automatic.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// Get all documents and print one document at a time:

var r = db.users.find().execute()
var doc
while (doc = r.fetchOne()) {
    print(doc)
}

// Get all documents as a list object:

var r = db.users.find().execute()
var list = r.fetchAll()
print(list)
print(list.length)
for (index in list) { 
    print(list[index].name) 
}

// And, use the list as JS array:
[...list].map(e =&amp;gt; e.name).forEach(e =&amp;gt; print(e, " "))
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Working with Relational Tables
&lt;/h2&gt;

&lt;p&gt;Perform CRUD operations on MySQL relational tables in the MySQL Shell.&lt;/p&gt;

&lt;p&gt;First, the table(s) to work with need to be created in MySQL Shell's SQL mode or in &lt;code&gt;mysql&lt;/code&gt; client. For example, we work with &lt;code&gt;cities&lt;/code&gt; table in the current schema.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;SQL&amp;gt; CREATE TABLE cities (city VARCHAR(20) NOT NULL PRIMARY KEY, state VARCHAR(2) NOT NULL);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;MySQL Shell JS mode:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;db.getTables()  // list all tables in the current database

db.cities.insert([ "city", "state" ]).values("New York", "NY")
db.cities.insert().values("Los Angeles", "CA")

db.cities.select()
db.cities.select(["city"]).where("state = 'NY'").orderBy("city asc")

db.cities.update().set("city", "Buffalo").where("city = 'New York'")

db.cities.delete().where("city = 'Buffalo'")
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The above CRUD operation functions have the same results as when used with SQL.&lt;/p&gt;

&lt;p&gt;Like the result set for the collections's &lt;code&gt;find&lt;/code&gt;, the table's &lt;code&gt;select&lt;/code&gt; also returns a &lt;code&gt;Result&lt;/code&gt; object. You can use the &lt;code&gt;fetchOne&lt;/code&gt; and &lt;code&gt;fetchAll&lt;/code&gt; methods on it.&lt;/p&gt;

&lt;p&gt;In addition, you can also run SQL operations using the &lt;code&gt;session&lt;/code&gt; object. For example, &lt;code&gt;session.sql("SELECT * FROM cities")&lt;/code&gt;. This returns a &lt;code&gt;SqlResult&lt;/code&gt; class object.&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The X DevAPI allows working with JSON data and relational table data within the same application program using the "NoSQL" syntax. This has advantages from the flexibility of the JSON document and the strict rules used with relational data.&lt;/p&gt;

&lt;p&gt;You can also use the &lt;code&gt;db.getCollectionAsTable("collection_name")&lt;/code&gt; to use the collection as table and use the table CRUD syntax on it. For example, &lt;code&gt;db.getCollectionAsTable("users").select()&lt;/code&gt;.&lt;/p&gt;




&lt;h3&gt;
  
  
  References
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://dev.mysql.com/doc/x-devapi-userguide/en/"&gt;X DevAPI User Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.mysql.com/doc/mysql-shell/8.0/en/"&gt;MySQL Shell 8.0&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://dev.mysql.com/doc/refman/8.0/en/document-store.html"&gt;Using MySQL as a Document Store&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;




</description>
      <category>mysql</category>
      <category>json</category>
      <category>nosql</category>
      <category>database</category>
    </item>
    <item>
      <title>Learning C programming again...</title>
      <dc:creator>Prasad Saya</dc:creator>
      <pubDate>Sat, 12 Aug 2023 10:10:43 +0000</pubDate>
      <link>https://dev.to/prsaya/learning-c-programming-again-58i0</link>
      <guid>https://dev.to/prsaya/learning-c-programming-again-58i0</guid>
      <description>&lt;p&gt;I am revisiting C programming after nearly 30 years. &lt;/p&gt;

&lt;p&gt;I first studied &lt;a href="https://en.wikipedia.org/wiki/C_(programming_language)"&gt;C programming language&lt;/a&gt; around 1991-1992. I was working as a programmer at a small software consulting company in Bangalore, India. I was mostly working with COBOL programming. I had taken a few days off from work and enrolled into a training program in Unix and C. The training was conducted by Digital Equipment Corporation (DEC) in India (DEC's Unix flavor was called as &lt;a href="https://en.wikipedia.org/wiki/Ultrix"&gt;Ultrix&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Though I learnt the C, I never got to use it; UNIX in various flavors, yes. Few weeks back I had purchased a copy of the book, &lt;strong&gt;&lt;em&gt;C Programming Language (second edition) by Brian W. Kernighan and Dennis M. Ritchie&lt;/em&gt;&lt;/strong&gt;. I am studying the book, trying the code samples and also solving few exercises.&lt;/p&gt;

&lt;p&gt;I completed the first chapter titled, &lt;strong&gt;CHAPTER 1: A Tutorial Introduction&lt;/strong&gt;. It is an introductory chapter, with basic programming topics, examples and exercises. The topics in general are: printing hello world, declaring variables and symbolic constants, using arithmetic expressions, using for and while statements, character input and output, arrays and character arrays, functions and arguments, external variables and scope.&lt;/p&gt;

&lt;p&gt;I had tried most of the exercises and here are eight of them from various sections in the chapter. The exercise solutions are based upon what I came to know about C from the first chapter of the book.&lt;/p&gt;

&lt;p&gt;I have posted the code from couple of exercise solutions below. The remaining are in a &lt;strong&gt;GitHub Gist&lt;/strong&gt; &lt;a href="https://gist.github.com/prsaya/97b57414a33c2c15bc4f3392a8c6aeae"&gt;C Programming Exercise Solutions&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;I had used the &lt;strong&gt;MinGW C compiler&lt;/strong&gt; on a Windows computer to compile the programs.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;&lt;em&gt;Here are the sections and the exercises:&lt;/em&gt;&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1.1 Getting Started&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;Exercise 1-1&lt;/em&gt; Run the "Hello, world" program on your system. Experiment with leaving out parts of the program to see what error messages you get.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;

/* The Hello world program */
int main() 
{ 
    printf("Hello World!\n");
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;1.2 Variables and Arithmetic Expressions&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;Exercise 1-3&lt;/em&gt; Modify the temperature conversion program to print a heading above the table. &lt;a href="https://gist.github.com/prsaya/97b57414a33c2c15bc4f3392a8c6aeae#file-ex_1_3-c"&gt;Solution&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1.3 The For Statement&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;Exercise 1-5&lt;/em&gt; Modify the temperature conversion program to print the table in reverse order, fom 300 degrees to 0.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;

/* Fahrenheit to celsius table - prints in reverse,
   for the fahrenheit 300 to 0 in steps of 20 */
int main()
{ 
    int fahr;

    printf("Fahrenheit\tCelsius\n");
    for (fahr = 300; fahr &amp;gt;= 0; fahr = fahr - 20)
        printf(" %3d\t\t%6.1f\n", fahr, (5.0 / 9.0) * (fahr - 32));
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;1.5 Character Input and Output&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;Exercise 1-8&lt;/em&gt; Write a program to count blanks, tabs and newlines. &lt;a href="https://gist.github.com/prsaya/97b57414a33c2c15bc4f3392a8c6aeae#file-ex_1_8-c"&gt;Solution&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1.6 Arrays&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;Exercise 1-13&lt;/em&gt; Write a program to print a histogram of the lenghts of the words in its input. It is easy to draw a histogram with the bars horizontal; a vertical orientation is challenging. &lt;a href="https://gist.github.com/prsaya/97b57414a33c2c15bc4f3392a8c6aeae#file-ex_1_13-c"&gt;Solution&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1.7 Functions&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;Exercise 1-15&lt;/em&gt; Rewrite the temperature conversion program of Section 1.2 to use a function for conversion. &lt;a href="https://gist.github.com/prsaya/97b57414a33c2c15bc4f3392a8c6aeae#file-ex_1_15-c"&gt;Solution&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1.9 Character Arrays&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;Exercise 1-19&lt;/em&gt; Write a function reverse(s) that reverses the character string s. Use it to write a program that reverses its input a line at a time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#include &amp;lt;stdio.h&amp;gt;

#define MAX_LINE_LEN    1000 /* Assume each line is limited to this length */

int get_line(char line[], int maxline);
void reverse(char s[]);

/* Program that reverses its input a line at a time.
   Uses a function reverse(s) that reverses the character string s. */
int main()
{
    char line[MAX_LINE_LEN];

    while((get_line(line, MAX_LINE_LEN)) &amp;gt; 0) {
        reverse(line);
        printf("%s\n", line);
    }

    return 0;
}

/* get_line: read a line into s, return length */
int get_line(char s[], int lim)
{
    int c, i;

    for (i = 0; i &amp;lt; lim-1 &amp;amp;&amp;amp; (c = getchar()) != EOF &amp;amp;&amp;amp; c != '\n'; ++i)
        s[i] = c;
    if (c == '\n') {
        s[i] = c;
        ++i;
    }
    s[i] = '\0';

    return i;
}

/* length: returns the length of string s */
int length(char s[]) 
{
    int i;

    i = 0;
    while (s[i] != '\0')
        ++i;
    return i;
}

/* copy: copy from into to; assume to is big enough */
void copy(char to[], char from[])
{
    int i;

    i = 0;
    while ((to[i] = from[i]) != '\0')
        ++i;
}

/* reverse: reverses the input string */
void reverse(char s1[])
{
    int i, j, len;

    len = length(s1); /* get length of the string */

    /* make copy of the original string */
    char s2[len];
    copy(s2, s1);

    /* make a reverse of the original string */
    j = 0;
    for (i = len-1; i &amp;gt;= 0; --i, ++j)
        s1[j] = s2[i];
}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;1.10 External Variables and Scope&lt;/strong&gt;&lt;br&gt;
&lt;em&gt;Exercise 1-23&lt;/em&gt; Write a program to remove all comments from a C program. Don't forget to handle quoted strings and character constants properly. C comments do not nest. &lt;a href="https://gist.github.com/prsaya/97b57414a33c2c15bc4f3392a8c6aeae#file-ex_1_23-c"&gt;Solution&lt;/a&gt;&lt;/p&gt;




</description>
      <category>c</category>
      <category>programming</category>
      <category>beginners</category>
    </item>
    <item>
      <title>My first personal website</title>
      <dc:creator>Prasad Saya</dc:creator>
      <pubDate>Thu, 06 Jul 2023 14:01:49 +0000</pubDate>
      <link>https://dev.to/prsaya/my-first-personal-website-8f3</link>
      <guid>https://dev.to/prsaya/my-first-personal-website-8f3</guid>
      <description>&lt;p&gt;Few weeks back I started working on a website for myself with an introduction and some work related details. I concluded with registering the domain and hosting the site today.&lt;/p&gt;

&lt;p&gt;The website has the usual home, posts, projects and about pages. These are HTML/CSS pages with some JavaScript coding.&lt;/p&gt;

&lt;p&gt;I also added a Photos page with couple of photos I had taken. This page is only navigable from the About page.&lt;/p&gt;

&lt;p&gt;Deciding what posts or content to include in the site is not an easy task. I think the website content is a constant work in progress.&lt;/p&gt;

&lt;p&gt;You can view the website at: &lt;a href="http://www.prasadsaya.com/"&gt;prasadsaya.com&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Notes about a NodeJS program I wrote at work - 2nd March, 2023</title>
      <dc:creator>Prasad Saya</dc:creator>
      <pubDate>Thu, 09 Mar 2023 11:52:24 +0000</pubDate>
      <link>https://dev.to/prsaya/notes-about-a-nodejs-program-i-wrote-at-work-2nd-march-2023-17h6</link>
      <guid>https://dev.to/prsaya/notes-about-a-nodejs-program-i-wrote-at-work-2nd-march-2023-17h6</guid>
      <description>&lt;p&gt;The app was about an ExpressJS web server accessing MySQL database. The client is written using the &lt;a href="https://ejs.co/"&gt;EJS&lt;/a&gt; - a templating language that lets generate HTML using JavaScript. I will briefly touch upon some aspects of the code for the server as well as the client.&lt;/p&gt;




&lt;h2&gt;
  
  
  MySQL Database Queries
&lt;/h2&gt;

&lt;p&gt;The database CRUD (Create, Read, Update and Delete) queries were written as stored procedures (or procedures). The procedures were called in the NodeJS program using the &lt;a href="https://www.npmjs.com/package/mysql"&gt;mysql&lt;/a&gt; library calls. An advantage of using the procedures is that the stored procedure is defined and stored in the database along with table, index, and other database object definitions. A call to the procedure executes it on the database server and returns the result. This also allows your application code to be clean and simple (avoiding the SQL query syntax details).&lt;/p&gt;

&lt;p&gt;A sample procedure code looks like the following. This code updates a table row based upon a provided &lt;code&gt;items&lt;/code&gt; table &lt;code&gt;id&lt;/code&gt; and &lt;code&gt;quantity&lt;/code&gt; values and returns the updated row count as a result.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;DELIMITER $$
DROP PROCEDURE IF EXISTS update_item;
CREATE PROCEDURE update_item(IN id INT, IN quantity_in INT)
BEGIN
    UPDATE items
    SET quantity = quantity + quantity_in 
    WHERE  item_id = id;

    SELECT ROW_COUNT() AS updated_count;
END$$
DELIMITER ;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The NodeJS code calling the procedure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const sql = "CALL update_item(?, ?)";
connection.query(sql, [ id, quantity ], function (error, result) {
    // work with the query result or the error object ...
})
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sometimes, I also had to use the async-await syntax for the database query code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// this in an async function ...
try {
    const query = util.promisify(connection.query).bind(connection);
    const result = await query(sql, [ id, quantity ]);
    // ...
}
catch(error) { 
// ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note that the &lt;code&gt;util&lt;/code&gt; in the above code is the NodeJS &lt;a href="https://nodejs.org/docs/latest-v14.x/api/util.html"&gt;util module&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  The App's Client
&lt;/h2&gt;

&lt;p&gt;This is a sample EJS client code used in the app:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;%- include("header", { title: title }); %&amp;gt;

&amp;lt;div&amp;gt;Browse items and perform edits on them here.
  &amp;lt;form action="item_edit" method="post"&amp;gt;
    &amp;lt;input type="hidden" name="_method" value="add" &amp;gt;
    &amp;lt;button type="submit"&amp;gt;&amp;lt;i class="fa fa-plus"&amp;gt;&amp;lt;/i&amp;gt; Add Item&amp;lt;/button&amp;gt;
  &amp;lt;/form&amp;gt;
&amp;lt;/div&amp;gt;

&amp;lt;table&amp;gt;
  &amp;lt;thead&amp;gt;
    &amp;lt;tr&amp;gt;
      &amp;lt;th&amp;gt;Id&amp;lt;/th&amp;gt;
      &amp;lt;th&amp;gt;Name&amp;lt;/th&amp;gt;
      &amp;lt;th&amp;gt;Quantity&amp;lt;/th&amp;gt;
      &amp;lt;th&amp;gt;Action&amp;lt;/th&amp;gt;
    &amp;lt;/tr&amp;gt;
  &amp;lt;/thead&amp;gt;
  &amp;lt;tbody&amp;gt;
    &amp;lt;% items.forEach(function(row) { %&amp;gt;
      &amp;lt;tr&amp;gt;
        &amp;lt;td&amp;gt;&amp;lt;%= row.item_id %&amp;gt;&amp;lt;/td&amp;gt;
        &amp;lt;td&amp;gt;&amp;lt;%= row.name %&amp;gt;&amp;lt;/td&amp;gt;
        &amp;lt;td&amp;gt;&amp;lt;%= row.quantity %&amp;gt;&amp;lt;/td&amp;gt;
        &amp;lt;td&amp;gt;
          &amp;lt;form action="item" method="post"&amp;gt;
            &amp;lt;input type="hidden" name="id" value=&amp;lt;%= row.item_id %&amp;gt; &amp;gt;
            &amp;lt;input type="hidden" name="_method" value="delete" &amp;gt;
            &amp;lt;button type="submit"&amp;gt;&amp;lt;i class="fa fa-trash"&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/button&amp;gt;
          &amp;lt;/form&amp;gt;
          &amp;lt;form action="item_edit" method="post"&amp;gt;
            &amp;lt;input type="hidden" name="_method" value="edit" &amp;gt;
            &amp;lt;input type="hidden" name="id" value=&amp;lt;%= row.item_id %&amp;gt; &amp;gt;
            &amp;lt;button type="submit"&amp;gt;&amp;lt;i class="fa fa-pencil"&amp;gt;&amp;lt;/i&amp;gt;&amp;lt;/button&amp;gt;
          &amp;lt;/form&amp;gt;
        &amp;lt;/td&amp;gt;
      &amp;lt;/tr&amp;gt;
    &amp;lt;% }); %&amp;gt;
  &amp;lt;/tbody&amp;gt;
&amp;lt;/table&amp;gt;

&amp;lt;%- include("footer"); %&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The screenshot of the client as seen in the browser window (only the relevant rendered HTML is shown):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--095sOvuE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5zaq78mv6kqmkysuonhu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--095sOvuE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_800/https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5zaq78mv6kqmkysuonhu.png" alt="Screenshot of the partial client user interface" width="800" height="506"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Comments
&lt;/h2&gt;

&lt;p&gt;A typical web app has aspects of database, a web server and a browser client. The web server provides the services to access the database and send data to the client. All these together are typically referred as a full-stack application.  &lt;/p&gt;

&lt;p&gt;Writing such an app is the full-stack development. Full stack development requires skills in programming specific languages (in this case NodeJS, JavaScript), databases and the client side scripting. In addition, the knowledge of how the components of the stack connect, interact and provide specific functionality. &lt;/p&gt;




</description>
      <category>node</category>
    </item>
    <item>
      <title>Notes about a NodeJS program I wrote at work - 22nd Feb, 2023.</title>
      <dc:creator>Prasad Saya</dc:creator>
      <pubDate>Thu, 23 Feb 2023 01:01:32 +0000</pubDate>
      <link>https://dev.to/prsaya/notes-about-a-nodejs-program-i-wrote-at-work-22nd-feb-2023-2m9</link>
      <guid>https://dev.to/prsaya/notes-about-a-nodejs-program-i-wrote-at-work-22nd-feb-2023-2m9</guid>
      <description>&lt;p&gt;The NodeJS program is about preparing data and sending a POST request to an API external to this app. The app receives a response from the request for further processing. An aspect of this app is making the POST request at a regular interval, for example every 6 hours. Finally, I needed to log the API calls to a file.&lt;/p&gt;

&lt;p&gt;In this post I discuss, in brief, the various libraries used to accomplish the task.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to make a job run every &lt;em&gt;n&lt;/em&gt; hours?
&lt;/h2&gt;

&lt;p&gt;I used a cron task scheduler library, the &lt;a href="https://www.npmjs.com/package/node-cron" rel="noopener noreferrer"&gt;node-cron&lt;/a&gt;. The scheduler code looked like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const cron = require("node-cron");
const CRON = "0 0 */6 * * *";
cron.schedule(CRON, async () =&amp;gt; {
    console.log("Making the API request.");
    // ...
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  How to make a POST request using form data?
&lt;/h2&gt;

&lt;p&gt;For this functionality, I used the &lt;a href="https://www.npmjs.com/package/form-data" rel="noopener noreferrer"&gt;form-data&lt;/a&gt; library. This allowed sending form data with an uploaded file and also set custom headers. For example, creating the form data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const FormData = require("form-data");
const formData = new FormData();
formData.append("mydata", "some data");
formData.append("myfile", fs.createReadStream("abc.xyz"));
const options = { method: "POST", body: formData, headers: { myhdr: "hdr value" } };
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Send the request and receive a response using &lt;a href="https://www.npmjs.com/package/node-fetch" rel="noopener noreferrer"&gt;node-fetch&lt;/a&gt; using the earlier created form data:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const fetch = require("node-fetch");
const resp = await fetch("http://www.example.com/someapi", options);
const json_data = await resp.json();
// Do something with the response data here ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;An aspect to note is that the functionality (or similar) of the &lt;code&gt;fetch&lt;/code&gt; npm package is the implementation in NodeJS 17.x &lt;a href="https://nodejs.org/docs/latest-v17.x/api/globals.html#fetch" rel="noopener noreferrer"&gt;fetch&lt;/a&gt;.&lt;/p&gt;




&lt;h2&gt;
  
  
  What logger?
&lt;/h2&gt;

&lt;p&gt;The logging needed to be both in the console as well as to a file. The logged message included a timestamp too. I used the &lt;a href="https://www.npmjs.com/package/winston" rel="noopener noreferrer"&gt;winston&lt;/a&gt; logging library. The logger code looked like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const winston = require("winston");
const logger = winston.createLogger({
    level: "info",
    format: winston.format.combine(winston.format.timestamp(), winston.format.json()),
    transports: [
        new winston.transports.File({ filename: "log_file_name.log" }),
        new winston.transports.Console(),  
    ],
});

logger.info({ message: "Logger started" });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Conclusion:
&lt;/h2&gt;

&lt;p&gt;I had used various libraries to accomplish a task. I note that the logging is the most common task and an important aspect of developing apps.&lt;/p&gt;




</description>
      <category>ai</category>
      <category>formatting</category>
      <category>productivity</category>
      <category>abotwrotethis</category>
    </item>
    <item>
      <title>Revisiting my first PHP app after a month and its improvements...</title>
      <dc:creator>Prasad Saya</dc:creator>
      <pubDate>Mon, 13 Feb 2023 09:17:09 +0000</pubDate>
      <link>https://dev.to/prsaya/revisiting-my-first-php-app-after-a-month-and-its-improvements-k1b</link>
      <guid>https://dev.to/prsaya/revisiting-my-first-php-app-after-a-month-and-its-improvements-k1b</guid>
      <description>&lt;p&gt;Last month (7th January 2023) I had posted an article on this site, &lt;a href="https://dev.to/prsaya/notes-about-my-first-php-app-2297"&gt;Notes about my first PHP app&lt;/a&gt;. It was a quiz app. It was part of my learning PHP.&lt;/p&gt;

&lt;p&gt;The present post is about writing similar app. The app's functionality is same. But, this time I had coded using some newer PHP features. Notable among them are the usage of data from a database. Another feature is the usage of a layout template with content from different actions. Finally, the app has a better look.&lt;/p&gt;




&lt;h2&gt;
  
  
  The Data
&lt;/h2&gt;

&lt;p&gt;The quiz data is now stored in a database. The MySQL Server has a &lt;code&gt;quiz&lt;/code&gt; database with two tables - &lt;code&gt;data&lt;/code&gt; and &lt;code&gt;options&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The data is created using SQL scripts. The app connects to the database and reads data from the tables using &lt;code&gt;mysqli&lt;/code&gt; APIs. You will notice that the data is normalized.&lt;/p&gt;

&lt;p&gt;The previous app's data was JSON documents stored in a file. Each JSON document represented a quiz item and had composite data types like arrays.&lt;/p&gt;




&lt;h2&gt;
  
  
  The App
&lt;/h2&gt;

&lt;p&gt;The app has following components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;DatabaseConnection&lt;/code&gt;: This class extends &lt;code&gt;mysqli&lt;/code&gt; class to create a database connection object.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;DatabaseTable&lt;/code&gt;:  An instance of this class is created for each table using the connection object. This has methods like, &lt;code&gt;findAll&lt;/code&gt;, &lt;code&gt;findById&lt;/code&gt;, &lt;code&gt;findByColumn&lt;/code&gt;, etc., to access the database data.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Controller&lt;/code&gt;: This class takes all the &lt;code&gt;DatabaseTable&lt;/code&gt; objects as input. An instance starts or uses an existing session. This has methods for each of the app's actions (start, play, and end). Each method returns the view template and the data to be rendered in it.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;index&lt;/code&gt;: This is the entry point to the app. This is also the entry point to each of the app's functions. This creates the database connection, the table and controller objects for each action. Based upon the action, specific controller method is executed. The output is rendered into the app's main layout template.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;home_html&lt;/code&gt;, &lt;code&gt;play_html&lt;/code&gt;, &lt;code&gt;end_html&lt;/code&gt; are the views for the start, the quiz play and the quiz end pages respectively. The &lt;code&gt;layout_html&lt;/code&gt; is the main template.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;styles.css&lt;/code&gt; is for better looks (or style) and &lt;code&gt;onload_js.js&lt;/code&gt; is JavaScript to set a button's state. &lt;code&gt;play_js.js&lt;/code&gt; has a JavaScript function that evaluates if a question is answered correctly and then makes an Ajax call to &lt;code&gt;score.php&lt;/code&gt; to update the score (which is tracked in a session variable).&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  App's Screenshots:
&lt;/h2&gt;

&lt;p&gt;Here are two screenshots of the app running in a browser - the landing and the quiz play pages.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5paqgkbs09u6d6gpdesk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5paqgkbs09u6d6gpdesk.png" alt="Quiz App's home page" width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fev105lp6rkkmlkabf3q2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fev105lp6rkkmlkabf3q2.png" alt="Quiz App's play page with quiz question and options" width="800" height="451"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This time in addition to object orientated classes, arrays (and its various functions like shuffle, extract, in_array) and get/post/session variables, notable PHP features used are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://www.php.net/manual/en/function.spl-autoload-register.php" rel="noopener noreferrer"&gt;spl_autoload_register&lt;/a&gt; for registering given function as &lt;code&gt;__autoload()&lt;/code&gt; implementation.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.php.net/manual/en/book.outcontrol.php" rel="noopener noreferrer"&gt;Output Buffering Control&lt;/a&gt; functions &lt;code&gt;ob_start&lt;/code&gt; and &lt;code&gt;ob_get_clean&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.php.net/manual/en/book.mysqli.php" rel="noopener noreferrer"&gt;MySQL Improved Extension&lt;/a&gt; with its object orientated APIs to connect to the database and read from the tables.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The app has a better structure and classes in reusable formats. These can be used in other applications with minor modifications. The app is structured to have more tables and more functionality. This is work in progress. The app has better looks due to improved CSS.&lt;/p&gt;

&lt;p&gt;The GitHub repository &lt;a href="https://github.com/prsaya/an-example-php-app.git" rel="noopener noreferrer"&gt;An Example PHP App&lt;/a&gt; has the source code. It also has details on MySQL Server 8 installation, &lt;code&gt;mysqli&lt;/code&gt; extension configuration, and the SQL scripts for creating the database with sample data. The app is developed using PHP 8.2 and the database is MySQL 5.5.&lt;/p&gt;




</description>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>Books I had read in the past decade or so...</title>
      <dc:creator>Prasad Saya</dc:creator>
      <pubDate>Thu, 19 Jan 2023 20:03:47 +0000</pubDate>
      <link>https://dev.to/prsaya/books-i-had-read-in-the-past-decade-or-so-5d26</link>
      <guid>https://dev.to/prsaya/books-i-had-read-in-the-past-decade-or-so-5d26</guid>
      <description>&lt;p&gt;&lt;em&gt;The picture above shows the actual books I have. I made this photograph today (13th Nov, 2023). I replaced the borrowed picture.&lt;/em&gt;&lt;/p&gt;




&lt;p&gt;I recently noted couple of posts on this website about books (both technical and non-technical). I had some thoughts and I am writing this about what books I had read in the past 10 years or so. I had written this in one sitting and without any plan on how to organize the list and what to write.&lt;/p&gt;

&lt;p&gt;I have been reading books of English language (mostly fiction) actively since I was in college. There is no specific pattern - I had read books as and I felt like. There were stretches of months and years I had not read any books.&lt;/p&gt;

&lt;p&gt;In the past decade I had been reading little bit and here are some of those books. These include fictional, non-fictional and software related.&lt;/p&gt;

&lt;p&gt;When I had an urge or time to read I found the books from various sources. Popular books lists, physical book stores, online book stores, libraries, references from other books or talks, book reviews, and also for specific purpose (this last category applies mostly to my profession).&lt;/p&gt;

&lt;p&gt;These books include eBooks and paperbacks.&lt;/p&gt;

&lt;p&gt;Some books are freely sourced (these are mostly from online resources like libraries), others purchased and few borrowed. &lt;/p&gt;

&lt;p&gt;Some of these are re-reads.&lt;/p&gt;

&lt;p&gt;Some of these are sitting on my bookshelf and some on my computer's hard drive or in the cloud.&lt;/p&gt;

&lt;p&gt;So, what are these books? I will touch on some of them and the experience from what I can recollect now. The list is in alphabetical order by author under each category.&lt;/p&gt;




&lt;h2&gt;
  
  
  Free eBooks
&lt;/h2&gt;

&lt;p&gt;These are a list of eBooks from free online sources. Most of these books are from the Project Gutenberg (it is an online library of free eBooks). The books are mostly fictional and popular classics. I have mentioned one book per author, but often it is more than one I had read from the same author.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Alexandre Dumas (The Count of Monte Cristo)&lt;/li&gt;
&lt;li&gt;Anton Chekov (Short Stories)&lt;/li&gt;
&lt;li&gt;Arthur Canon Doyle (stories about the Sherlock Holmes) - this is a re read for 3rd or 4th time&lt;/li&gt;
&lt;li&gt;Charles Dickens (Great Expectations)&lt;/li&gt;
&lt;li&gt;D. H. Lawrence (Sons and Lovers) - I had read the other book, the famous and once banned book - The Lady Chatterley's Lover.&lt;/li&gt;
&lt;li&gt;Darwin, Charles (The Voyage of the Beagle)&lt;/li&gt;
&lt;li&gt;E.M. Foster (A Room with a View) - I had watched the movie too.&lt;/li&gt;
&lt;li&gt;Franz Kafka (Metamorphosis)&lt;/li&gt;
&lt;li&gt;Fyodor Dostoyevsky (Brothers Karamazov)&lt;/li&gt;
&lt;li&gt;G.K. Chesterton (The Man Who Knew Too Much)&lt;/li&gt;
&lt;li&gt;Gabriel Garcia Marquez (One Hundred Years of Solitude)&lt;/li&gt;
&lt;li&gt;George Eliot (Middlemarch)&lt;/li&gt;
&lt;li&gt;H. G. Wells (War of the Worlds)&lt;/li&gt;
&lt;li&gt;Harriet Beecher Stowe (Uncle Tom's Cabin)&lt;/li&gt;
&lt;li&gt;Jack London (Call of the Wild) - I had read the White Fang long time back.&lt;/li&gt;
&lt;li&gt;James Joyce (The Dubliners) - I had read the Ulysses too (by the same author).&lt;/li&gt;
&lt;li&gt;Kate Chopin (The Awakening, and Selected Short Stories)&lt;/li&gt;
&lt;li&gt;L. M. Montgomery (Anne of Green Gables)&lt;/li&gt;
&lt;li&gt;Leo Tolstoy (War and Peace)&lt;/li&gt;
&lt;li&gt;Margaret Mitchell (Gone with the wind) - This one I had found in an online book library from Australia.&lt;/li&gt;
&lt;li&gt;Mark Twain (Adventures of Tom Sawyer) - this was a re read for the 3rd time.&lt;/li&gt;
&lt;li&gt;Miguel de Cervantes (Don Quixote)&lt;/li&gt;
&lt;li&gt;Nevil Shute (Trustee from Toolroom) - This I found from a reference in another book.&lt;/li&gt;
&lt;li&gt;Oscar Wilde (The Importance of Being Earnest)&lt;/li&gt;
&lt;li&gt;P. G. Wodehouse (My Man Jeeves)&lt;/li&gt;
&lt;li&gt;Robert Louis Stevenson (Treasure Island)&lt;/li&gt;
&lt;li&gt;Rudyard Kipling (The Man Who Would Be King)&lt;/li&gt;
&lt;li&gt;Shaw, Bernard (Pygmalion)&lt;/li&gt;
&lt;li&gt;William Shakesphere (Much Ado about Nothing) - Yes, I had watched the movie, first.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Fictional eBooks
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Ayn Rand (The Fountainhead)&lt;/li&gt;
&lt;li&gt;J. D. Salinger (Catcher on the Rye)&lt;/li&gt;
&lt;li&gt;Larry McMurty (Lonesome Dove) - A long story about cowboys.&lt;/li&gt;
&lt;li&gt;Pearl S. Buck (The Good Earth) - A story of rural Chinese people and their lives during 20th century&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Fictional Paperbacks
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Aleksandr Solzhenitsyn (The First Circle) - A Russian language book translated to English. I came to know about this book from its reference in another book.&lt;/li&gt;
&lt;li&gt;Alex Haley (Roots).&lt;/li&gt;
&lt;li&gt;Banana Yoshimoto (Kitchen) - An English translation of a Japanese book. &lt;/li&gt;
&lt;li&gt;Eleanor H. Porter (Polyanna) - Had picked up at a bookstore casually. It is about an orphaned child.&lt;/li&gt;
&lt;li&gt;Fuminori Nakamura (The Thief) - An English translation of a Japanese book. Had picked up at a book store casually. This book is a hard cover.&lt;/li&gt;
&lt;li&gt;J. R. R. Tolkien (The Hobbit) - I haven't read the LOTR, yet.&lt;/li&gt;
&lt;li&gt;James Redfield (The Celestine Prophecy) - I came to know about this book as I watched the move made from this book at a retreat.&lt;/li&gt;
&lt;li&gt;Jandy Nelson (I'll Give You the Sun) - This is one of the most recent reads. This is a story about teenagers.&lt;/li&gt;
&lt;li&gt;O. Henry (100 Selected Stories) - Had picked up in an online store casually. I had liked its colorful cover - An Illustration of Manhattan. The book is all short stories. It has a beautiful story called as "The Gift of the Magi".&lt;/li&gt;
&lt;li&gt;Richard Bach (Jonathan Livingston Seagull, a story) - Small book under 90 pages. Had picked up in an online store casually. Had read it more than once.&lt;/li&gt;
&lt;li&gt;Ruzbeh N. Bharucha (The Fakir) - Came to know about the book from a library.&lt;/li&gt;
&lt;li&gt;Saul Bellow (Herzog) - Came to know about this book from a book listing.&lt;/li&gt;
&lt;li&gt;Toni Morrison (The Bluest Eye) - Had picked up at a bookstore casually.&lt;/li&gt;
&lt;li&gt;W. Somerset Maugham (Of Human Bondage) - Had picked up at a bookstore casually.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Non Fiction Books
&lt;/h2&gt;

&lt;p&gt;These are related to psychology, self help, biography, philosophy and religion. All are paperbacks, except the Quiet and Walden which I got from the iTunes store. Walden was a free copy.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Anne Fadiman (Ex Libris) - It is about books, reading books and the experience.&lt;/li&gt;
&lt;li&gt;Carl Sagan (Cosmos)&lt;/li&gt;
&lt;li&gt;Carlo Rovelli (Seven Brief Lessons on Physics)&lt;/li&gt;
&lt;li&gt;Dacher Keltner (Born to be Good) - This book is about human feelings.&lt;/li&gt;
&lt;li&gt;David Herbert Donald (Lincoln) - A bigraphical book on Abraham Lincoln.&lt;/li&gt;
&lt;li&gt;Ekhart Tolle (The Power of Now) - Teachings from a contemporary spiritual teacher.&lt;/li&gt;
&lt;li&gt;Eknath Eswaran (The Dhammapada) - This is about Lord Buddha's teachings.&lt;/li&gt;
&lt;li&gt;Harini Nagendra and Seema Mundoli (Cities and Canopies - Trees in Indian Cities)&lt;/li&gt;
&lt;li&gt;His Holiness Dalai Lama of Tibet (Freedom in Exile) - An autobiographical book.&lt;/li&gt;
&lt;li&gt;J. Krishnamurti (Happy is the Man who is Nothing - Letters to a Young Friend) - A tiny book of less than 70 pages.&lt;/li&gt;
&lt;li&gt;James Allen (A Man Thinketh)&lt;/li&gt;
&lt;li&gt;James Doty (Into the Magic Shop) - A biographical book, I came to know about from an interview the author had given in a wellness magazine. One of my recent reads.&lt;/li&gt;
&lt;li&gt;M. K. Gandhi (My Experiments with Truth) - An autobiographical book.&lt;/li&gt;
&lt;li&gt;Malcolm Gladwell (What the Dog Saw) - Came to know about the book from a library and had found the title rather amusing.&lt;/li&gt;
&lt;li&gt;Max Muller (Ramakrishna, his life and sayings)&lt;/li&gt;
&lt;li&gt;Michael Singer (The Untethered Soul - A journey beyond yourself) - This is one of those books I haven't completed reading yet, though I got it couple of years back.&lt;/li&gt;
&lt;li&gt;Nelson Mandela (Long Walk to Freedom) - An autobiographical book.&lt;/li&gt;
&lt;li&gt;Paul Pearsall (The Heart's Code) -  A beautiful book about human heart (the physical heart too).&lt;/li&gt;
&lt;li&gt;Susan Cain (Quiet) - This book is to get to know more about quiet people.&lt;/li&gt;
&lt;li&gt;Swami Vivekananda (Complete works - 9 volumes) - These I read over a period of 10 months.&lt;/li&gt;
&lt;li&gt;Thomas A. Harris (I'm Ok. You're OK)&lt;/li&gt;
&lt;li&gt;Thoreau, Henry David (Walden)&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Poetry
&lt;/h2&gt;

&lt;p&gt;Rabindranath Tagore (Gitanjali) - This is the only poetry book I had ever read (other than from the school text books). This is a paperback I had purchased from a bookstore rather casually.&lt;/p&gt;




&lt;h2&gt;
  
  
  Books on Software
&lt;/h2&gt;

&lt;p&gt;This list does not specify the author and the title of the books. It is a general listing of topics only.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Programming&lt;/strong&gt;: Java EE, Java 7, 8 and 9, Spring, JavaServer Faces, Haskell, Golang, NodeJS, JavaScript, HTML &amp;amp; CSS, Hadoop, MySQL.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Software Engineering&lt;/strong&gt;: Data Structures &amp;amp; Algorithms, Unit Testing, Refactoring, Clean Code, Object Oriented Analysis &amp;amp; Design, UML.&lt;/li&gt;
&lt;/ul&gt;




</description>
      <category>datascience</category>
      <category>analytics</category>
      <category>visualization</category>
      <category>discuss</category>
    </item>
    <item>
      <title>Notes about my first PHP app</title>
      <dc:creator>Prasad Saya</dc:creator>
      <pubDate>Sat, 07 Jan 2023 07:06:08 +0000</pubDate>
      <link>https://dev.to/prsaya/notes-about-my-first-php-app-2297</link>
      <guid>https://dev.to/prsaya/notes-about-my-first-php-app-2297</guid>
      <description>&lt;p&gt;This is my first app written using PHP. I have been studying and trying coding PHP casually for the last couple of weeks. I am using the PHP Manual and other online free resources for my study. &lt;/p&gt;

&lt;p&gt;I am an experienced programmer using other languages. I am able to select some basic and intermediate topics and was trying the code in small scripts. On the way, I thought of building a small example app. This would allow me try some features as I build the functionality for the app. It was a quiz app.&lt;/p&gt;

&lt;p&gt;In this post I talk about the app and the PHP features I had used.&lt;/p&gt;




&lt;h2&gt;
  
  
  Contents
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;The Data&lt;/li&gt;
&lt;li&gt;The App&lt;/li&gt;
&lt;li&gt;Utility Files&lt;/li&gt;
&lt;li&gt;Data Exceptions&lt;/li&gt;
&lt;li&gt;Development&lt;/li&gt;
&lt;li&gt;PHP Features&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  The Data &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;Like most of apps there is data, the quiz data. This is a Json file, &lt;code&gt;quiz_data.txt&lt;/code&gt;, with an array of documents. Each document has the quiz question, options, option type, answers, and notes fields. &lt;/p&gt;

&lt;p&gt;Here is a sample Json document:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"id"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"question"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Is &amp;lt;code&amp;gt;1800&amp;lt;/code&amp;gt; a leap year?."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"type"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"S"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"options"&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;"(a) True"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"(b) False"&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;"answers"&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;"b"&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;"notes"&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;"False."&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="s2"&gt;"A leap year is divisible by &amp;lt;code&amp;gt;4&amp;lt;/code&amp;gt;, but not divisible by &amp;lt;code&amp;gt;100&amp;lt;/code&amp;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;"When divisible by &amp;lt;code&amp;gt;100&amp;lt;/code&amp;gt;, must also be divisible by &amp;lt;code&amp;gt;400&amp;lt;/code&amp;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="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I had used the PHP functions &lt;code&gt;file_get_contents&lt;/code&gt; and &lt;code&gt;json_decode&lt;/code&gt; to read the Json file and convert documents as associate arrays. This array data is used in the app.&lt;/p&gt;




&lt;h2&gt;
  
  
  The App &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;The app's code is in few files. These are &lt;code&gt;.php&lt;/code&gt;, &lt;code&gt;.js&lt;/code&gt;, &lt;code&gt;.css&lt;/code&gt; and &lt;code&gt;.txt&lt;/code&gt; files. Some of the PHP files are for starting the app, navigating to other pages and for performing user interaction. Other PHP files are utility files. These have class, function and constant definitions.&lt;/p&gt;

&lt;p&gt;The app starter PHP script is the &lt;code&gt;quiz_start.php&lt;/code&gt;. This reads the Json file and prepares data for using in the app. This page has navigation to the following &lt;code&gt;quiz_form.php&lt;/code&gt; page.&lt;/p&gt;

&lt;p&gt;The quiz_form page shows the quiz questions, allows user to select answers, checks the correctness of the selections, and then navigates to the next question. Finally, when the questions are exhausted, shows a result page &lt;code&gt;quiz_result.php&lt;/code&gt;. That’s the end of the app. The user has an option to navigate back to the starter page from here or quit.&lt;/p&gt;

&lt;p&gt;The user can also navigate to the starter page from quiz_form page.&lt;/p&gt;

&lt;p&gt;The starter page also starts a session. The quiz data array is stored in a &lt;code&gt;$_SESSION&lt;/code&gt; automatic global variable for usage in the app's other pages. Other data tracked as session variables are the quiz data counter and correct answers counter. These are used in accessing the quiz question to be displayed and for the result page to show the percentage success.&lt;/p&gt;

&lt;p&gt;The quiz_form page reads the sessions variables and updates the counters. There is also a &lt;code&gt;quiz_app.js&lt;/code&gt; JavaScript file with a function to evaluate the answer for each question. The user selects the answers from the options and clicks the Answer JavaScript button. This executes the JS function and shows if the user selections were correct or not.&lt;/p&gt;




&lt;h2&gt;
  
  
  Utility Files &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;These are the included files. These are accessed in the PHP pages using the &lt;code&gt;require&lt;/code&gt; or &lt;code&gt;include&lt;/code&gt; expressions. The app has three include files: &lt;code&gt;file_util.php&lt;/code&gt;, &lt;code&gt;exception_util.php&lt;/code&gt; and &lt;code&gt;constants.php&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;These have definitions of &lt;code&gt;FileUtil&lt;/code&gt;, &lt;code&gt;ExceptionUtil&lt;/code&gt; and &lt;code&gt;Constants&lt;/code&gt; classes.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;FileUtil&lt;/code&gt; class has a function that reads the Json file, decodes it to PHP array and returns the array. The &lt;code&gt;ExceptionUtil&lt;/code&gt; has a function to handle the exceptions that can occur in accessing, reading, and decoding the input file data. &lt;code&gt;Constants&lt;/code&gt; class defines a set of constants used throughout the app (for example, the input Json data file name).&lt;/p&gt;




&lt;h2&gt;
  
  
  Data Exceptions &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;The app starts with reading the Json file.&lt;/p&gt;

&lt;p&gt;There is a possibility that the input file may not exist (or have an incorrect name), or is empty or has incorrectly formatted Json. These three exceptional situations are handled in the app. In these scenarios the exception handling code shows appropriate message on the starter page and exits the app.&lt;/p&gt;




&lt;h2&gt;
  
  
  Development &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;The app is developed using PHP 8.2.0, Apache HTTP Server 2.4, HTML, CSS and JavaScript on a Windows computer.&lt;/p&gt;

&lt;p&gt;The source code is structured in the directories (dir) as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;app root (dir)
    quiz_start.php
    quiz_form.php
    quiz_result.php
    redirect_start.php
    data (dir)
        quiz_data.txt
    public (dir)
        quiz_app.js
        quiz_app_styles.css
    includes (dir)
        constants.php
        file_util.php
        exception_util.php
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  PHP Features &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;These are some notable functions, class, variables, type, class, expression and OO features used in the app. &lt;/p&gt;

&lt;p&gt;From the PHP Manual:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Functions: &lt;a href="https://www.php.net/manual/en/function.file-get-contents.php" rel="noopener noreferrer"&gt;file_get_contents&lt;/a&gt;, &lt;a href="https://www.php.net/manual/en/function.json-decode.php" rel="noopener noreferrer"&gt;json_decode&lt;/a&gt;, &lt;a href="https://www.php.net/manual/en/function.iconv.php" rel="noopener noreferrer"&gt;iconv&lt;/a&gt;, &lt;a href="https://www.php.net/manual/en/function.session-start" rel="noopener noreferrer"&gt;session_start&lt;/a&gt;, &lt;a href="https://www.php.net/manual/en/function.isset" rel="noopener noreferrer"&gt;isset&lt;/a&gt;, &lt;a href="https://www.php.net/manual/en/function.header" rel="noopener noreferrer"&gt;header&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Variables: &lt;a href="https://www.php.net/manual/en/reserved.variables.session.php" rel="noopener noreferrer"&gt;$_SESSION&lt;/a&gt;, &lt;a href="https://www.php.net/manual/en/reserved.variables.post" rel="noopener noreferrer"&gt;$_POST&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Type: &lt;a href="https://www.php.net/manual/en/language.types.array.php" rel="noopener noreferrer"&gt;Arrays&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Class: &lt;a href="https://www.php.net/manual/en/class.jsonexception" rel="noopener noreferrer"&gt;JsonException&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Expression: &lt;a href="https://www.php.net/manual/en/function.require.php" rel="noopener noreferrer"&gt;require&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;OO Features: &lt;a href="https://www.php.net/manual/en/language.oop5.basic.php" rel="noopener noreferrer"&gt;Classes&lt;/a&gt;, &lt;a href="https://www.php.net/manual/en/language.oop5.static.php" rel="noopener noreferrer"&gt;Static methods&lt;/a&gt; and &lt;a href="https://www.php.net/manual/en/language.oop5.constants.php" rel="noopener noreferrer"&gt;Class constants&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Configuration: &lt;a href="https://www.php.net/manual/en/ini.core.php#ini.include-path" rel="noopener noreferrer"&gt;include path&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Conclusion &lt;a&gt;&lt;/a&gt;
&lt;/h2&gt;

&lt;p&gt;This is a &lt;strong&gt;picture of the app&lt;/strong&gt; running in a web browser. It’s the quiz_form page. It shows the quiz data as the user selects the answer options and clicks the Answer button. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4xws0a5xbr6uxjbwjw09.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4xws0a5xbr6uxjbwjw09.png" alt="Quiz App's quiz_form page showing the quiz data" width="800" height="441"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;Writing the code as I was studying and learning helped me grasp the PHP features well. These are some of the features I had used in this app. Until now I am feeling quite good about the PHP.&lt;/p&gt;

&lt;p&gt;Here is the app's &lt;strong&gt;source code&lt;/strong&gt; at the GitHub: &lt;a href="https://github.com/prsaya/a-demo-quiz-app-using-php.git" rel="noopener noreferrer"&gt;a-demo-quiz-app-using-php&lt;/a&gt;.&lt;/p&gt;




&lt;p&gt;That said, there are two features I had explored but didn’t include in coding the app. &lt;/p&gt;

&lt;p&gt;The first is the namespaces. &lt;/p&gt;

&lt;p&gt;The second is usage of classes and objects for the quiz data. This also meant serialization of objects and the implementation of the two magic methods &lt;code&gt;__serialize&lt;/code&gt; and &lt;code&gt;__unserialize&lt;/code&gt; (for the object to be used as session variable). This coding worked fine, but it is more code and processing. I will be working on it further and try to use this efficiently.&lt;/p&gt;




</description>
      <category>discuss</category>
    </item>
    <item>
      <title>Notes about a website and apps</title>
      <dc:creator>Prasad Saya</dc:creator>
      <pubDate>Fri, 23 Dec 2022 15:36:36 +0000</pubDate>
      <link>https://dev.to/prsaya/notes-about-a-website-and-apps-ogi</link>
      <guid>https://dev.to/prsaya/notes-about-a-website-and-apps-ogi</guid>
      <description>&lt;p&gt;As a software engineer you encounter various things - technologies for sure. As you learn, you also want to try those and share and show those. This is part of the experience. This post is about one such experience. This has various aspects and lets see what they are.&lt;/p&gt;

&lt;p&gt;Back in year 2012, I was studying to upgrade my Java programmer certification to Java 7 (this certification was conducted by Oracle Corporation and was known as OCPJP). It was a challenging toipc. Java had included many newer features in Java 7 -  newer language features, NIO 2, improvements in JDBC and concurrency. The topics were huge. I had to write lots of sample code for learning the features. My learning references were Java Language Specification, Java API docs and other online references. I was not using any preparation guides, but I had some prior knowledge of Java programming.&lt;/p&gt;

&lt;p&gt;After completing the exam, I had to do something with all the material and the exam experience. I had this idea that I can share some of this with other Java programmers. So, this idea developed into a quiz app. I went on to create some quiz data, and wrote a Java Swing desktop app. The app was a quiz app. &lt;/p&gt;

&lt;p&gt;How do I share this app with others? &lt;/p&gt;

&lt;p&gt;After some research, I wanted to create a website and share this app. The result was a website hosted on a Java enabled webserver. The desktop quiz app was deployed as a Java Web Start application. Java Web Start technology allowed deploy a Java desktop app on a Java enabled webserver and have the app invoked on a website as a link.&lt;/p&gt;

&lt;p&gt;The app was called Java Quiz Player.&lt;/p&gt;

&lt;p&gt;Next, I went on and got a domain "javaquizplayer.com" for the website. It took sometime to figure the name and it sounded alright to me. I also found a Java webserver hosting provider to deploy the website and the app.&lt;/p&gt;

&lt;p&gt;Finally, I had the website online on 1st November, 2012. It was a basic website with one page and with a few lines explaining the website and the app. It had one link to start the app. It was also the first time wrote HTML and CSS. To run the app you needed a JRE (Java Runtime) on your computer. &lt;/p&gt;

&lt;p&gt;I went on to share the website link on some of the online forums and hence fulfilled my idea about sharing.&lt;/p&gt;

&lt;p&gt;The website was &lt;a href="http://www.javaquizplayer.com" rel="noopener noreferrer"&gt;http://www.javaquizplayer.com&lt;/a&gt;. The first installment of it looked like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F59qxj1esesfl10ts76j4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F59qxj1esesfl10ts76j4.png" alt="Picture of javaquizplayer.com website on November 2012" width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Another thing I did was to get a copyright registration certificate for the  website content as well as the computer programs.&lt;/p&gt;




&lt;p&gt;Further in year 2013, I started writing few blog posts on my website. &lt;/p&gt;

&lt;p&gt;Now, the website had more than one page. This was followed by an online Java quiz as a web app. The online quiz app was a Java web app written using Servlets, JSP, HTML, CSS and JavaScript. The website itself was self built with HTML4 and CSS.&lt;/p&gt;

&lt;p&gt;As I wrote more, I was sharing these posts and quiz with other forums. It was a rich experience for me. Experience to create, learn, improve and share.&lt;/p&gt;

&lt;p&gt;In year 2016, I started writing some demo desktop apps with detailed articles explaining the complete development of the apps. The apps were mostly Java Swing or JavaFX for GUI and database for storing the app's data. The databases included H2, HSQLDB, Apache Derby, MongoDB and used JPA, Spring JDBC, etc., for data access. These were posted as Examples on my website. There were more blog posts including some Java EE related articles. &lt;/p&gt;

&lt;p&gt;I also started writing on other websites and forums.&lt;/p&gt;

&lt;p&gt;As part of my programming journey, I was also attending various meetups held locally. These were on various technologies and Java  was one of my favoured topic. At one of the meetups in year 2016 or 2017, a Dr. Venkat Subramaniam made a presentation on Java 8, Functional Programming, its features, advantages, usage, etc. It was a great presentation, I was impressed and taken to Java 8 immediately. &lt;/p&gt;

&lt;p&gt;Thus, I started learning functional programming, not of Java, but using Haskell. After a couple of books and some coding I was confident about functional programming. Now, I started learning Java's functional programming features - the streams, functions, lambdas, method reference expressions, their application and usage in collections, file IO, etc. Then, I took the Java 8 upgrade certification successfully.&lt;/p&gt;

&lt;p&gt;That done, I wrote a quiz cards app. The content was the Java 8's functional programming topics and related features as I had studied for the Java 8 certification. It was JavaFX GUI app and was deployed as a Java Web Start app on my website. The app was called as Java Quiz Card Player. This was in September 2017.&lt;/p&gt;

&lt;p&gt;Since then, I had couple more articles and some refinements (HTML5 and better CSS is one of them) for the website and its content. The website's landing page as of now:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvm69vndhhdjv778hx16k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fvm69vndhhdjv778hx16k.png" alt="Picture of javaquizplayer.com website landing page as of December 2022" width="800" height="442"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;p&gt;It was interesting for me to look back some ten years before and noted that lot of things happened during a website and its content. &lt;/p&gt;

&lt;p&gt;Functional programming along with Object-Oriented capabilities makes Java a versatile programming language to learn and use. Also, notably the newer programming paradigm like Reactive programming is applied to Java too, the RxJava, and I came to learn little bit of that too.&lt;/p&gt;




</description>
      <category>beginners</category>
      <category>career</category>
      <category>learning</category>
      <category>discuss</category>
    </item>
  </channel>
</rss>
