• Tidak ada hasil yang ditemukan

Note I truncated the table formatting rows (the dashed lines) from the examples for brevity

Now, let’s see how the data looks if we use a SELECT SQL statement. In this case, we’ll just select the two rows by city name because they are unique in the table. The following is an excerpt of the results.

MySQL localhost:33060+ ssl SQL > SELECT * FROM city WHERE Name in ('Charlotte', 'Daytona') \G

*************************** 1. row ***************************

ID: 3818 Name: Charlotte CountryCode: USA

District: North Carolina

Info: {"Population": 540828}

*************************** 2. row ***************************

ID: 4080 Name: Charlotte CountryCode: USA

District: North Carolina

ChapTer 4 The MySQL SheLL

Info: {"Population": 792862, "Places_of_interest": [{"name": "NASCAR Hall of Fame"}, {"name": "Charlotte Motor Speedway"}]}

*************************** 3. row ***************************

ID: 4081 Name: Daytona CountryCode: USA District: Florida

Info: {"Population": 590280, "Places_of_interest": [{"name":

"Daytona Beach"}, {"name": "Motorsports Hall of Fame of America"}, {"name":

"Daytona Motor Speedway"}]}

That’s interesting, but it doesn’t answer the question we want to ask. That is, which cities have places of interest? To do that, we need to use a number of special functions designed for the JSON data type. All of the functions begin with the name JSON_*. Let’s see each of these in turn starting with a way to search for rows that have a specific key in the JSON document. In this case, we select all of the data for rows that have places of interest.

To determine if a JSON document has a specific key, we use the JSON_CONTAINS_

PATH() function. Recall a path is simply a resolution of the keys in the document. In this case, we want to know if the JSON document contains a path for Places_of_interest.

Because the function returns a 0 for no match and 1 for at least one match, we check to see if it is equal to 1. You can omit the equality, but it is best to be pedantic when experimenting with new features and commands. We also use the ‘all’ option to tell the function to return all of the matches (values) as opposed to ‘one’, which returns only the first occurrence. You can also use the slightly more correct IS NOT NULL comparison.

MySQL localhost:33060+ ssl SQL > SELECT * FROM city WHERE JSON_CONTAINS_

PATH(info, 'all', '$.Places_of_interest') = 1 \G

*************************** 1. row ***************************

ID: 4080 Name: Charlotte CountryCode: USA

District: North Carolina

Info: {"Population": 792862, "Places_of_interest": [{"name": "NASCAR Hall of Fame"}, {"name": "Charlotte Motor Speedway"}]}

167

*************************** 2. row ***************************

ID: 4081 Name: Daytona CountryCode: USA District: Florida

Info: {"Population": 590280, "Places_of_interest": [{"name":

"Daytona Beach"}, {"name": "Motorsports Hall of Fame of America"}, {"name":

"Daytona Motor Speedway"}]}

2 rows in set (0.00 sec)

Now, let’s say we only want to see those places of interest and not the entire JSON document. In this case, we need to use the JSON_EXTRACT() function to extract the values from the document. In particular, we want to search the info column for all values in the array Places_of_interest. Although that seems complicated, it isn’t too bad as you can see in the following.

MySQL localhost:33060+ ssl SQL > SELECT Name, District, JSON_

EXTRACT(info, '$.Places_of_interest') as Sights FROM city WHERE JSON_

EXTRACT(info, '$.Places_of_interest') IS NOT NULL \G

*************************** 1. row ***************************

Name: Charlotte District: North Carolina

Sights: [{"name": "NASCAR Hall of Fame"}, {"name": "Charlotte Motor Speedway"}]

*************************** 2. row ***************************

Name: Daytona District: Florida

Sights: [{"name": "Daytona Beach"}, {"name": "Motorsports Hall of Fame of America"}, {"name": "Daytona Motor Speedway"}]

2 rows in set (0.00 sec)

Now, what if we wanted to only retrieve the values for the Places_of_interest array? In this case, we can use a special format of the JSON access to get these values from the array. The following demonstrates the technique. Note the portion highlighted in bold.

ChapTer 4 The MySQL SheLL

MySQL localhost:33060+ ssl SQL > SELECT Name, District, JSON_

EXTRACT(info, '$.Places_of_interest[*].name') as Sights FROM city WHERE JSON_EXTRACT(info, '$.Places_of_interest') IS NOT NULL \G

*************************** 1. row ***************************

Name: Charlotte District: North Carolina

Sights: ["NASCAR Hall of Fame", "Charlotte Motor Speedway"]

*************************** 2. row ***************************

Name: Daytona District: Florida

Sights: ["Daytona Beach", "Motorsports Hall of Fame of America", "Daytona Motor Speedway"]

2 rows in set (0.00 sec)

Okay, now that’s a lot easier to read, isn’t it? It’s also a bit messy SQL command.

And if all of that seemed a bit painful, you’re right, it was. Working with JSON data in SQL works with the help of the JSON functions, but it is an extra step and can be a bit confusing in syntax. See the online MySQL reference manual for full explanations of each of the JSON_* functions.

If you’ve used the old MySQL client much to query data with wide rows, chances are you’ve used the \G option to display the results in a vertical format, which makes reading the data easier. With the shell, we don’t have that option but we can display data using the --json option. Although the option is easier to read, it tends to be a bit verbose. We will see this in action in the Python section.

Finally, we can remove the rows with the DELETE SQL command as shown in the following.

MySQL localhost:33060+ ssl SQL > DELETE FROM city WHERE Name in ('Charlotte', 'Daytona');

Query OK, 3 rows affected (0.00 sec)

Now, let’s see the same operations performed using JavaScript.

169