developing modern applications with the mysql document ... · the examples in this workbook. if you...

34
Developing Modern Applications with the MySQL Document Store and NodeJS [HOL1706] Jesper Wisborg Krogh Senior Principal Technical Support Engineer Lig Isler-turmelle Principle Technical Support Engineer

Upload: others

Post on 05-Oct-2020

0 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Developing Modern Applications with the MySQL Document ... · the examples in this workbook. If you are attending the hands-on labs session Developing Modern Applications with the

Developing Modern Applications with the MySQL Document Store and NodeJS [HOL1706]

Jesper Wisborg Krogh

Senior Principal Technical Support Engineer

Lig Isler-turmelle Principle Technical Support Engineer

Page 2: Developing Modern Applications with the MySQL Document ... · the examples in this workbook. If you are attending the hands-on labs session Developing Modern Applications with the

Prerequisites

Note: This is not required when using the laptops at HOL1706 at Oracle OpenWorld

2018.

It is assumed the following software is already installed on the machine where you try

the examples in this workbook. If you are attending the hands-on labs session

Developing Modern Applications with the MySQL Document Store and NodeJS

[HOL1706] at Oracle OpenWorld 2018, you do not need to do anything, and you can skip

to the next section.

Required Software List

MySQL Server 8.0.12 or later

MySQL Shell 8.0.12 or later

MySQL Connector/Node.js 8.0.12 or later

Node.js 8.12 (other 8.X versions should work as well; other versions may require

changes to the examples)

Data List

The world database: http://downloads.mysql.com/docs/world.sql.gz

The world_x database: http://downloads.mysql.com/docs/world_x-db.tar.gz

An empty hol1706 schema

Installing the Software

The following steps can be used to install the required software on Oracle Linux 7. For

other platforms the steps will be different.

# Install the latest public yum repo

# and enable the required ol7_developer repos:

cd /etc/yum.repos.d/

mv public-yum-ol7.repo public-yum-ol7.repo.bak

wget http://yum.oracle.com/public-yum-ol7.repo

yum-config-manager --enable ol7_developer_nodejs8

yum-config-manager --enable ol7_developer_EPEL

# Install MySQL Repo

wget https://dev.mysql.com/get/mysql80-community-release-el7-

1.noarch.rpm

yum install mysql80-community-release-el7-1.noarch.rpm

# Install MySQL Server, Shell, and connectors

Page 3: Developing Modern Applications with the MySQL Document ... · the examples in this workbook. If you are attending the hands-on labs session Developing Modern Applications with the

yum install mysql-community-client \

mysql-community-common \

mysql-community-devel \

mysql-community-libs \

mysql-community-libs-compat \

mysql-community-server \

mysql-shell \

nodejs-8*

# Start MySQL Server for the first time

# (initializes the data directory)

# and update the root password.

systemctl start mysqld

passwd=$(grep 'A temporary password is generated for root@localhost'

/var/log/mysqld.log | sed -re 's/^.* (.+)$/\1/')

mysql --user=root --password="${passwd}" --connect-expired-password -e

"SET PASSWORD = '<some secure password>'"

unset passwd

Note: It is recommended not to put the password on the command line. The above is

done for simplicity.

Installing Data

The following instructions assume the previously mentioned software has been

installed, that MySQL Server has been started, and that the root password has been

updated (it is set to an expired password by default that can be found in

/var/log/mysqld.log after MySQL has been started the first time).

The data needed for this hands-on lab can be installed following these steps:

wget http://downloads.mysql.com/docs/world.sql.zip

wget http://downloads.mysql.com/docs/world_x-db.zip

unzip world.sql.zip

unzip world_x-db.zip

mysql --user=root --password \

--execute "SOURCE world.sql; SOURCE world_x-db/world_x.sql;"

HOL Information

The following information is useful for the hands-on lab session at Oracle OpenWorld

2018:

Linux Username lab

Linux Password oracle

MySQL Username hol1706

MySQL Password hol@OOW18

Page 4: Developing Modern Applications with the MySQL Document ... · the examples in this workbook. If you are attending the hands-on labs session Developing Modern Applications with the

MySQL Schemas hol1706 world world_x

Connectors and APIs Installed MySQL Connector/Node.js 8.0.12 @mysql/xdevapi

MySQL Connector/Python 8.0.12 mysql.connector (PEP 249 Python DB API) mysqlx (X DevAPI – for the Document Store) MySQL Connector/J 8.0.12 java.sql.*

Documentation This workbook as well as documentation for the X DevAPI, MySQL Connector/Node.js, MySQL Connector/Python, and MySQL Shell can be found in the /home/lab/docs directory. Firefox is set to open with an overview of the available documentation as the home page.

Tip: A login path has been configured for the hol1706 user, so it is not necessary to

specify the username and password when using the mysql command-line client or

MySQL Shell.

The MySQL Document Store

The MySQL Document Store was developed throughout the MySQL Server 5.7 lifetime.

The server-side is implemented through the X plugin (called mysqlx in the

information_schema.PLUGINS view), and was first introduced as a beta release with

MySQL Server 5.7.12. The X plugin reached general availability (GA) status with MySQL

Server 8.0.11 and is now a built-in plugin and enabled by default. That is, on the server-

side you do not need to do anything to start using the MySQL Document Store.

mysql> SELECT *

FROM information_schema.PLUGINS

WHERE PLUGIN_NAME = 'mysqlx'\G

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

PLUGIN_NAME: mysqlx

PLUGIN_VERSION: 1.0

PLUGIN_STATUS: ACTIVE

Page 5: Developing Modern Applications with the MySQL Document ... · the examples in this workbook. If you are attending the hands-on labs session Developing Modern Applications with the

PLUGIN_TYPE: DAEMON

PLUGIN_TYPE_VERSION: 80012.0

PLUGIN_LIBRARY: NULL

PLUGIN_LIBRARY_VERSION: NULL

PLUGIN_AUTHOR: Oracle Corp

PLUGIN_DESCRIPTION: X Plugin for MySQL

PLUGIN_LICENSE: GPL

LOAD_OPTION: ON

1 row in set (0.00 sec)

There are a few more components to the MySQL Document Store:

X Plugin: This is the server-side plugin that provides support for the X DevAPI.

X Protocol: The protocol used for an application to communicate with the X

Plugin.

The X DevAPI: The API used with the X Protocol.

Collectively these components are known as the MySQL Document Store.

X Plugin Port and Other Variables

Because the X Plugin uses a different protocol to the traditional MySQL protocol, it

needs to listen to a different port than the usual. The X Plugin by default uses port

33060. This can be configured using the mysqlx_port option. Similarly, if you want to

connect using a UNIX socket file, you need a separate socket file.

All of the variables for the X Plugin are prefixed mysqlx_. The complete list of variables

with their default values (using the MySQL Server RPM for Oracle Linux/RHEL 7) is:

mysql> SELECT *

FROM performance_schema.global_variables

WHERE VARIABLE_NAME LIKE 'mysqlx%';

+-----------------------------------+-----------------------------+

| VARIABLE_NAME | VARIABLE_VALUE |

+-----------------------------------+-----------------------------+

| mysqlx_bind_address | * |

| mysqlx_connect_timeout | 30 |

| mysqlx_document_id_unique_prefix | 0 |

| mysqlx_idle_worker_thread_timeout | 60 |

| mysqlx_interactive_timeout | 28800 |

| mysqlx_max_allowed_packet | 67108864 |

| mysqlx_max_connections | 100 |

| mysqlx_min_worker_threads | 2 |

| mysqlx_port | 33060 |

| mysqlx_port_open_timeout | 0 |

| mysqlx_read_timeout | 30 |

| mysqlx_socket | /var/run/mysqld/mysqlx.sock |

| mysqlx_ssl_ca | |

| mysqlx_ssl_capath | |

| mysqlx_ssl_cert | |

Page 6: Developing Modern Applications with the MySQL Document ... · the examples in this workbook. If you are attending the hands-on labs session Developing Modern Applications with the

| mysqlx_ssl_cipher | |

| mysqlx_ssl_crl | |

| mysqlx_ssl_crlpath | |

| mysqlx_ssl_key | |

| mysqlx_wait_timeout | 28800 |

| mysqlx_write_timeout | 60 |

+-----------------------------------+-----------------------------+

21 rows in set (0.00 sec)

Several of the options have counterparts for the old MySQL protocol; for these the

variable names are the same just with mysqlx_ prefixed. For the purpose of this hands-

on lab, the default values can be used.

The X DevAPI

From an end user perspective, the most interesting part of the MySQL Document Store

is the X DevAPI. This is the API used to interact with the MySQL Document Store from

your programs and from MySQL Shell.

The X DevAPI is designed from the ground up with modern day usage in mind. It is

available for a range of languages, for example: Python (MySQL Connector/Python),

JavaScript (MySQL Connector/Node.js), PHP (mysql_xdevapi PECL extension), Java

(MySQL Connector/J), C++ (MySQL Connector/C++), DotNet (MySQL Connector/NET).

The X DevAPI is uniform across the supported programming languages while still

maintaining the characteristics of the language. An example if the method to get a

session is get_session() in Python but getSession() in Node.js.

The X DevAPI has three different parts. Which part you should use depends on how you

want to interact with MySQL:

Collections: The create-read-update-delete (CRUD) methods to work with JSON

documents, i.e. using MySQL as a document store. This is a NoSQL API.

SQL Tables: The CRUD methods to work with SQL (relational) tables. This is a

NoSQL API.

SQL: This can be used to execute arbitrary SQL statements against both

collections and SQL tables.

The easiest way to try the X DevAPI is to use MySQL Shell. MySQL Shell is a relatively

new command-line tool that not only support SQL statements but also Python and

JavaScript. This makes it possible to test code before implementing it in an actual

program, or use MySQL Shell to execute scripts that include use of Python or JavaScript

routines.

Note: Python and JavaScript in MySQL Shell do not use the connectors, so while the API

is the same, there are some differences in their use.

Page 7: Developing Modern Applications with the MySQL Document ... · the examples in this workbook. If you are attending the hands-on labs session Developing Modern Applications with the

Start MySQL Shell

As MySQL Shell support JavaScript and the X DevAPI, it is a good tool for testing code

interactively. MySQL Shell is started using the mysqlsh command in the terminal.

Optionally specify the language mode you want to use. The language mode can also be

set after starting MySQL Shell. The following table shows how to specify the language

mode on the command-line or the MySQL shell prompt.

Language Mode Command-Line MySQL Shell Prompt

JavaScript --js \js

Python --py \py

SQL --sql \sql

The default language mode is JavaScript. The exercises in this lab will include examples

of changing the language mode.

Tip: When you switch language mode, you can keep using your existing connection if

you are already connected to a MySQL instance.

For now, start MySQL Shell without any arguments:

[lab@localhost ~]$ mysqlsh

MySQL Shell 8.0.12

Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights

reserved.

Oracle is a registered trademark of Oracle Corporation and/or its

affiliates. Other names may be trademarks of their respective

owners.

Type '\help' or '\?' for help; '\quit' to exit.

mysql-js>

You can connect to MySQL using the \connect command:

mysql-js> \connect hol1706@localhost

Creating a session to 'hol1706@localhost'

Fetching schema names for autocompletion... Press ^C to stop.

Your MySQL connection id is 12 (X protocol)

Server version: 8.0.12 MySQL Community Server - GPL

No default schema selected; type \use <schema> to set one.

mysql-js> session

<Session:hol1706@localhost>

Page 8: Developing Modern Applications with the MySQL Document ... · the examples in this workbook. If you are attending the hands-on labs session Developing Modern Applications with the

No password is required as MySQL Shell has been set up to fetch the password from a

login path. If this has not been done, MySQL Shell will interactively ask for the password

and offer to store it for you.

The session can be accessed through the session object. This can be useful for example

to fetch a schema, controlling transactions, etc. You will see examples of this later in the

lab.

You can now set the default schema (this can also be done when creating the

connection) using the \use command:

mysql-py> \use hol1706

Default schema `hol1706` accessible through db.

Notice how MySQL Shell assigned the hol1706 schema to the db object. You can now

use the db object to access the schema specific methods.

Before continuing, let’s pause for a moment to consider the prompt.

The Prompt

The default prompt includes information about the connection, whether it uses SSL, the

default schema, and the language mode. An example of the default prompt can be seen

in the following figure:

MySQL Shell in the hands-on lab virtual machine has been set up to use the

Powerline+Awesome fonts. This gives a prompt with the same information as the

default prompt but using some additional custom characters:

Page 9: Developing Modern Applications with the MySQL Document ... · the examples in this workbook. If you are attending the hands-on labs session Developing Modern Applications with the

It is beyond the scope of this lab session to go through the installation of the Powerline

and Awesome fonts. If you are interested, you can see an example of installing the

required fonts in https://mysql.wisborg.dk/2018/09/04/awesome-mysql-shell-prompt/.

Before continuing learning how to work with the MySQL Document Store from MySQL

Shell, let’s look at what you can do, if you need help.

Built-In Help

A great feature in MySQL Shell is also the ability to obtain help directly within MySQL

Shell. This is not limited to the standard --help command-line argument; it extends to

within MySQL Shell including for each object type.

You can get general help, for example about the commands available (you have already

used the \connect and \use commands):

mysql-js> \?

The Shell Help is organized in categories and topics. To get help for a

specific category or topic use: \? <pattern>

The <pattern> argument should be the name of a category or a topic.

The pattern is a filter to identify topics for which help is required,

it can

use the following wildcards:

- ? matches any single charecter.

- * matches any character sequence.

The following are the main help categories:

Page 10: Developing Modern Applications with the MySQL Document ... · the examples in this workbook. If you are attending the hands-on labs session Developing Modern Applications with the

- AdminAPI Introduces to the dba global object and the InnoDB

cluster

administration API.

- Shell Commands Provides details about the available built-in shell

commands.

- ShellAPI Contains information about the shell and util global

objects

as well as the mysql module that enables executing

SQL on

MySQL Servers.

- SQL Syntax Entry point to retrieve syntax help on SQL

statements.

- X DevAPI Details the mysqlx module as well as the capabilities

of the

X DevAPI which enable working with MySQL as a

Document Store

The available topics include:

- The dba global object and the classes available at the AdminAPI.

- The mysqlx module and the classes available at the X DevAPI.

- The mysql module and the global objects and classes available at the

ShellAPI.

- The functions and properties of the classes exposed by the APIs.

- The available shell commands.

- Any word that is part of an SQL statement.

SHELL COMMANDS

The shell commands allow executing specific operations including

updating the

shell configuration.

The following shell commands are available:

- \ Start multi-line input when in SQL mode.

- \connect (\c) Connects the shell to a MySQL server and assigns

the

global session.

- \exit Exits the MySQL Shell, same as \quit.

- \help (\?,\h) Prints help information about a specific topic.

- \history View and edit command line history.

- \js Switches to JavaScript processing mode.

- \nowarnings (\w) Don't show warnings after every statement.

- \option Allows working with the available shell options.

- \py Switches to Python processing mode.

- \quit (\q) Exits the MySQL Shell.

- \reconnect Reconnects the global session.

- \rehash Refresh the autocompletion cache.

- \source (\.) Loads and executes a script from a file.

- \sql Switches to SQL processing mode.

Page 11: Developing Modern Applications with the MySQL Document ... · the examples in this workbook. If you are attending the hands-on labs session Developing Modern Applications with the

- \status (\s) Print information about the current global

session.

- \use (\u) Sets the active schema.

- \warnings (\W) Show warnings after every statement.

GLOBAL OBJEECTS

The following modules and objects are ready for use when the shell

starts:

- db Used to work with database schema objects.

- dba Used for InnoDB cluster administration.

- mysql Support for connecting to MySQL servers using the classic

MySQL

protocol.

- mysqlx Used to work with X Protocol sessions using the MySQL X

DevAPI.

- session Represents the currently open MySQL session.

- shell Gives access to general purpose functions and properties.

- sys Gives access to system specific parameters.

- util Global object that groups miscellaneous tools like upgrade

checker.

For additional information on these global objects use: <object>.help()

EXAMPLES

\? AdminAPI

Displays information about the AdminAPI.

\? \connect

Displays usage details for the \connect command.

\? checkInstanceConfiguration

Displays usage details for the dba.checkInstanceConfiguration

function.

\? sql syntax

Displays the main SQL help categories.

The examples at the end shows how you can get additional help. For example, to learn

how to use the \connect command:

mysql-js> \? connect

NAME

connect - Establishes the shell global session.

SYNTAX

shell.connect(connectionData[, password])

WHERE

connectionData: the connection data to be used to establish the

session.

Page 12: Developing Modern Applications with the MySQL Document ... · the examples in this workbook. If you are attending the hands-on labs session Developing Modern Applications with the

password: The password to be used when establishing the session.

DESCRIPTION

This function will establish the global session with the received

connection data.

As the help is very extensive, the whole output will not all be included here.

You can also get help directly about an object you are working with. For example, you

have the db object with the hol1706 schema. To get help about the db object, use the

help() method of the object:

mysql-js> db.help()

NAME

Schema - Represents a Schema as retrived from a session created

using the

X Protocol.

DESCRIPTION

View Support

MySQL Views are stored queries that when executed produce a

result set.

FUNCTIONS

createCollection(name)

Creates in the current schema a new collection with the

specified

name and retrieves an object representing the new

collection

created.

As the help output shows, a schema object for example has a method called

createCollection(). You can get additional help about the createCollection()

method by passing that as an argument to the help() method:

mysql-py> db.help("createCollection")

NAME

createCollection - Creates in the current schema a new collection

with

the specified name and retrieves an object

representing the new collection created.

SYNTAX

<Schema>.createCollection(name)

WHERE

name: the name of the collection.

RETURNS

Page 13: Developing Modern Applications with the MySQL Document ... · the examples in this workbook. If you are attending the hands-on labs session Developing Modern Applications with the

the new created collection.

DESCRIPTION

To specify a name for a collection, follow the naming conventions

in

MySQL.

Note that to get help for SQL statement, you must be connected to a MySQL instance,

and you either need to be in the SQL language mode or explicitly tell MySQL Shell that

you want help for an SQL statement. For example: \? SQL Syntax/SELECT.

Feel free to execute the help commands as you go through the exercises.

Built-in Objects

You have already encountered some of the built-in objects of MySQL Shell: The session

and db objects. There are more however built-in objects. From the output of \? you

executed a little earlier:

db: Used to work with database schema objects.

dba: Used for InnoDB cluster administration.

mysql: Support for connecting to MySQL servers using the classic MySQL

protocol.

mysqlx: Used to work with X Protocol sessions using the MySQL X DevAPI.

session: Represents the currently open MySQL session.

shell: Gives access to general purpose functions and properties.

sys: Gives access to system specific parameters.

util: Global object that groups miscellaneous tools like upgrade checker.

The two most useful for this lab are the db and session objects.

You are now ready to create a collection.

Lab Exercises

This lab will primarily use Node.js directly, however the collection is initially created

using MySQL Shell. You can also execute the exercises in MySQL Shell, but there will be

some differences due to MySQL Shell using a synchronous execution model whereas

Node.js is asynchronous. The general use of the X DevAPI will however be similar.

Tip: Most of the Node.js examples are also available in the /home/lab/bin directory.

When this is the case, the file name will be visible from the caption to the example.

If you wish to reset the city collection, you can execute the reset_city.sh script.

Page 14: Developing Modern Applications with the MySQL Document ... · the examples in this workbook. If you are attending the hands-on labs session Developing Modern Applications with the

Create Collection

Collections are the containers for the documents. In the SQL world a collection would be

called a table. A collection is always located in a schema (database). You can create a

collection using the createCollection() method which is part of the db object. The

method takes the name of the new collection as a string. For example to create the city

collection using MySQL Shell and keep a reference to the collection in the city object:

mysql-js> city = db.createCollection("city")

<Collection:city>

What does a collection look like? You can check the definition of the underlying table

using a SHOW CREATE TABLE SQL query:

mysql-py> \sql

Switching to SQL mode... Commands end with ;

Fetching table and column names from `hol1706` for auto-completion...

Press ^C to stop.

mysql-sql> SHOW CREATE TABLE city\G

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

Table: city

Create Table: CREATE TABLE `city` (

`doc` json DEFAULT NULL,

`_id` varbinary(32) GENERATED ALWAYS AS

(json_unquote(json_extract(`doc`,_utf8mb4'$._id'))) STORED NOT NULL,

PRIMARY KEY (`_id`)

) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci

1 row in set (0.0007 sec)

mysql-sql> \js

Switching to JavaScript mode...

mysql-js>

This shows how you can change mode to use SQL if that is more convenient. At the end

the mode is changed back to JavaScript. The collection consists of an InnoDB table with

a normal column called doc and a generated column called _id. The doc column is

where the JSON document is stored. The _id column is generated by extracting the

value of the _id object at the base of the JSON document; this is the primary key of the

table and must always be present. If you create a document without the _id field,

MySQL will auto-generate one.

Tip: If you later need to get an object for the city collection again, you can get it using: city = db.getCollection("city")

Now that there is a collection to work with, let’s discuss how you can use MySQL

Connector/Node.js with that collection.

Page 15: Developing Modern Applications with the MySQL Document ... · the examples in this workbook. If you are attending the hands-on labs session Developing Modern Applications with the

Using MySQL Connector/Node.js

To create a Node.js program using MySQL Connector/Node.js you need to import the

@mysql/xdevapi module:

const mysqlx = require('@mysql/xdevapi');

It is also recommended to enable strict mode.

A connection is created using the getSession() method (this is also available in MySQL

Shell). You need to pass the connections options, either directly as options or as an URI.

An example of creating the sessions is:

#!/usr/bin/env node

'use strict';

const mysqlx = require('@mysql/xdevapi');

const mysqlArgs = {

host: 'localhost',

port: 33060,

password: 'hol@OOW18',

user: 'hol1706',

};

const session = mysqlx.getSession(mysqlArgs);

console.log(session);

process.exit(0);

Script file: getSession.js

This just creates the connection, then logs what the sessions is:

Promise { <pending> }

mysqlx.getSession() returns Promise, i.e. it is for asynchronous use .

In real-world examples, you should not include all the connection options in the

program itself; that is neither secure nor practical.

Warning: Do not include the connection options – particularly the password – in the

source code of real program. In the example it is done to keep the initial connection

example self-contained.

One option is to have the connections in a custom module:

const config = {};

config.mysqlArgs = {

Page 16: Developing Modern Applications with the MySQL Document ... · the examples in this workbook. If you are attending the hands-on labs session Developing Modern Applications with the

host: 'localhost',

port: 33060,

password: 'hol@OOW18',

user: 'hol1706',

};

config.schema = 'hol1706';

module.exports = config;

Script: config.js

If you save this as config.js in the same directory as your Node.js programs, you can

now connect like:

#!/usr/bin/env node

'use strict';

const mysqlx = require('@mysql/xdevapi');

const config = require('./config')

mysqlx.getSession(config.mysqlArgs)

.then(function(session) {

console.log('The session is ready for use.');

process.exit(0);

});

Script: getSession2.js

This also adds the use of the then() method to tell what should happen once the

promise is fulfilled.

To actually work with a collection, you first need retrieve the schema, then the

collection. The schema object is obtained using the getSchema() method of the session,

likewise the collection object is obtained using the getCollection() method of the

schema:

#!/usr/bin/env node

'use strict';

const mysqlx = require('@mysql/xdevapi');

const config = require('./config')

mysqlx.getSession(config.mysqlArgs)

.then(function (session) {

const schema = session.getSchema(config.schema);

return schema.getCollection('city');

})

Page 17: Developing Modern Applications with the MySQL Document ... · the examples in this workbook. If you are attending the hands-on labs session Developing Modern Applications with the

process.exit(0);

Script: getCollection.js

The code is nested using the then() method to work with the asynchronous nature of

Node.js. An alternative way to get the collections is:

#!/usr/bin/env node

'use strict';

const mysqlx = require('@mysql/xdevapi');

const config = require('./config');

(async function() {

let session;

try {

session = await mysqlx.getSession(config.mysqlArgs);

const schema = session.getSchema(config.schema);

const city = schema.getCollection('city');

console.log('The city collection is ready to use');

} catch (err) {

console.error(err.message);

} finally {

session && await session.close();

}

})();

Script: getCollection2.js

This uses async and await with asynchronous functions to avoid the nesting. This

requires Node.js 8.0 or later. However, enough of creating connections without using

them. It is time to add some data and query it.

Executing Document Store Queries

Executing queries is a topic too large to cover in full in this lab, however you are

encouraged to experiment yourself using the documentation as help. Here three cities

will be added to the collection, two queries will be executed to find cities matching

given criteria, documents will be updated, and finally deleted.

Adding Documents

Since JSON documents are native to JavaScript (JSON stands for JavaScript Object

Notation), they work out of the box without any special consideration. The X DevAPI

supports both inserting a single document at a time or multiple documents. Let’s look at

Page 18: Developing Modern Applications with the MySQL Document ... · the examples in this workbook. If you are attending the hands-on labs session Developing Modern Applications with the

an example of two add statements inside the same transaction adding a total of three

documents.

#!/usr/bin/env node

'use strict';

const mysqlx = require('@mysql/xdevapi');

const config = require('./config');

// Define the documents to add

// Populations are from the world sample database, so quite outdated.

const sanFrancisco = {

'Name': 'San Francisco',

'Demographics': {

'Population': 776733,

},

'Geography': {

'Country': 'United States of America',

'State': 'California',

'Location': {'Type': 'Point', 'Coordinates': [-122.419,

37.779]},

},

'Capital': false,

};

const london = {

'Name': 'London',

'Demographics': {

'Population': 7285000,

},

'Geography': {

'Country': 'United Kingdom',

'State': 'England',

'Location': {'Type': 'Point', 'Coordinates': [-0.143, 51.501]},

},

'Capital': true,

};

const washington = {

'Name': 'Washington',

'Demographics': {

'Population': 572059,

},

'Geography': {

'Country': 'United States of America',

'State': 'District of Columbia',

'Location': {'Type': 'Point', 'Coordinates': [-77.035, 38.889]}

},

'Capital': true,

};

(async function() {

let session;

Page 19: Developing Modern Applications with the MySQL Document ... · the examples in this workbook. If you are attending the hands-on labs session Developing Modern Applications with the

try {

session = await mysqlx.getSession(config.mysqlArgs);

const schema = session.getSchema(config.schema);

const city = schema.getCollection('city');

await session.startTransaction();

// Add a single city (San Francisco) in one statement

const result1 = city.add(sanFrancisco).execute();

if (result1.getWarningsCount() > 0) {

console.error(result1.getWarningsCount()

+ 'warnings occurred when adding San Francisco:\n'

+ result1.getWarnings());

await session.rollback();

await session.close();

process.exit(1);

} else {

console.log('Adding San Francisco with ID: '

+ result1.getGeneratedIds());

}

// Add two cities (London + Washington) in one statement

const stmt = city.add(london);

stmt.add(washington);

const result2 = await stmt.execute();

if (result2.getWarningsCount() > 0) {

console.error(result2.getWarningsCount()

+ 'warnings occurred when adding London and

Washington\n'

+ result2.getWarnings());

await session.rollback();

await session.close();

process.exit(1);

} else {

console.log('Adding London and Washington with IDs: '

+ result2.getGeneratedIds());

}

await session.commit();

} catch (err) {

console.error(err.message);

} finally {

session && await session.close();

}

})();

Script: add.js

The example starts out defining JSON documents for three cities. The location of a city is

specified using the GeoJSON format (http://geojson.org/ and

https://en.wikipedia.org/wiki/GeoJSON). Since the JSON documents are schemaless,

Page 20: Developing Modern Applications with the MySQL Document ... · the examples in this workbook. If you are attending the hands-on labs session Developing Modern Applications with the

you are of course free to choose whatever format you wish, but if you want to add an

index for the location (see later), then MySQL expects the format to be GeoJSON.

The actual work is all done inside the async function. The collection is obtained as

before, then a transaction is started. The MySQL Document Store has full transactional

support including for savepoints. If any warnings occur while adding documents, the

transaction will be rolled back and the program will exit with the error code 1.

The city of San Francisco is added by itself. This is done using a chained statement where

the statement is created and executed in one. In contrast London and Washington is

added using three separate lines of code. You could also have written that as:

const result2 = await city.add(london).add(washington).execute()

Or you can choose a mix. The workflow will often dictate what works the best, for

example if the documents are added in a loop, then separate lines of code will work the

best. It is also possible to add several documents in one add() call by passing the

documents as an array.

In MySQL Connector/Node.js it is always required to call execute() to execute the

statement. This is in contrast with MySQL Shell for interactive queries without assigning

the result to a variable.

After each execute(), the number of warnings is checked and if any occurred they are

logged and the program exits. Warnings are often a sign of something not working as

expected, so it is important always to check the warnings and handle them as necessary.

The earlier you add support for handling warnings to your programs, the easier it.

Now there is some data, let’s query it.

Finding Documents

The main method to query documents is the find() method. It takes an argument with

the filter to apply to the documents. Additional modifications of the query can be made

with methods applied to the statement returned by find(). Each of the statement

methods return the statement itself (except execute() which returns the result), so

you can keep modifying the statement either in separate lines of code or by chaining.

You can then use the following methods to modify the query:

fields(): Specify which fields to return from the matching documents.

groupBy(): Which fields to group the result by.

having(): A filter that is applied after the data has been grouped.

sort(): Which fields to sort the result by.

Page 21: Developing Modern Applications with the MySQL Document ... · the examples in this workbook. If you are attending the hands-on labs session Developing Modern Applications with the

limit(): The maximum number of documents to return.

offset(): The offset to use together with the limit() method.

lockExclusive(): Take an exclusive lock on the matching documents.

lockShared(): Take a shared lock on the matching documents.

bind(): Used to assign values when parameters are used to set the filter

condition.

execute(): Execute the query – a document result object is returned.

Most of these methods are also available when modifying or deleting documents. Let’s

try to see it in use in a program that will log the total number of documents and the

cities in the United States:

#!/usr/bin/env node

'use strict';

const mysqlx = require('@mysql/xdevapi');

const config = require('./config');

(async function() {

let session;

let docs = [];

function storeResult(doc) {

docs.push(doc);

}

try {

session = await mysqlx.getSession(config.mysqlArgs);

const schema = session.getSchema(config.schema);

const city = schema.getCollection('city');

// Find the cities in the United States

const stmt = city.find('Geography.Country = :country')

.fields('Name', 'Geography.State AS State').sort('Name');

stmt.bind('country', 'United States of America');

const result = await stmt.execute(storeResult);

for (let i = 0; i < docs.length; i++) {

console.log(i + ': ' + docs[i]['Name'] + ', ' +

docs[i]['State'])

}

} catch (err) {

console.error(err.message);

} finally {

session && await session.close();

}

})();

Script: find.js

Page 22: Developing Modern Applications with the MySQL Document ... · the examples in this workbook. If you are attending the hands-on labs session Developing Modern Applications with the

There are a couple of things worth nothing in the example:

The fields in the filter, fields, and for sorting are given as JSON paths (except that

$. to denote the root of the document is optional).

Filters are written directly as a statement – MySQL will figure the rest out. This

makes it simple to write conditions.

The name of the country to filter by is given as a parameter with the actual value

specified in the call to bind(). This has the advantages that MySQL will ensure

the value gets escaped, and that it is possible to reuse the statement, if you need

to execute the same statement multiple times with different values.

The resulting documents are sent one by one to the callback function given as an

argument to execute().

The output of running the program is:

0: San Francisco, California

1: Washington, District of Columbia

It is worth considering how the fields are specified in a bit more detail.

Fields and JSON Paths

The field can either be a JSON path or an expression (possibly referencing one or more

fields in the JSON document). A JSON path is created as:

The document root is represented by $. Except for specifying fields for an index

(more later) it is optional whether $ is included in the path. This makes it simple

to specify top level objects as you just need to use the name as in the previous

example.

A dot (.) is used to separate elements. For example, if you have: {

"Red": {

"Pink": "FFC0CB",

"Pure_red": "FF0000",

"Maroon": "800000"

}

} Then to get the hex value for Maroon you can use $.Red.Maroon .

* is a wildcard that means “all members”. The wildcard can also be used as

[prefix]**{suffix} where the prefix is optional and the suffix is mandatory.

For arrays square brackets can be used to return an element. [N] returns the Nth

element (0-based) and [*] returns all elements (same as not specifying the

brackets at all).

The first find() example was a fairly simple query, so let’s look at an example using the

spatial information.

Page 23: Developing Modern Applications with the MySQL Document ... · the examples in this workbook. If you are attending the hands-on labs session Developing Modern Applications with the

Spatial Query

In MySQL 8.0 there is support for spatial reference systems (SRIDs), so spatial

calculations can be made accurately. Since the locations of the cities in the sample

collection are in the GeoJSON format, they can be used to find spatial properties such as

the distance between the city and some other point. The following example sets a

reference point at the location of San Francisco and calculates the distance to the cities

and includes those further away than 1000 kilometers.

#!/usr/bin/env node

'use strict';

const mysqlx = require('@mysql/xdevapi');

const config = require('./config');

(async function() {

let session;

let docs = [];

let distance_km;

try {

session = await mysqlx.getSession(config.mysqlArgs);

const schema = session.getSchema(config.schema);

const city = schema.getCollection('city');

// Get the location of San Francisco

// This could have been obtained from a query

const sf_loc = '{"Type": "Point", "Coordinates": [-122.419,

37.779]}';

// Define how the distance is calculated:

// ST_Distance(ref_location, city_location)

// Each location is obtained using ST_GeomFromGeoJSON() which

// converts a location in GeoJSON format to the representation

// used internally in MySQL.

const distance = 'ST_Distance(ST_GeomFromGeoJSON('

+ sf_loc + ', 1, 4326), '

+ 'ST_GeomFromGeoJSON(Geography.Location, 1, 4326))';

// Find the distance for each city to San Francisco

const stmt = city.find(`${distance} > :min_distance`)

.fields('Name', `${distance} AS Distance`)

.sort(distance);

const result = await stmt.bind('min_distance', 1000*1000)

.execute(doc => docs.push(doc));

for (let i = 0; i < docs.length; i++) {

distance_km = (docs[i]['Distance']/1000).toFixed(0);

console.log(`${i}: ${docs[i]['Name']}: ${distance_km} km`);

}

Page 24: Developing Modern Applications with the MySQL Document ... · the examples in this workbook. If you are attending the hands-on labs session Developing Modern Applications with the

} catch (err) {

console.error(err.message);

} finally {

session && await session.close();

}

})();

Script: find2.js

The formula for getting the distance is to convert the GeoJSON location to the internal

representation using the ST_GeomFromGeoJSON() function

(https://dev.mysql.com/doc/refman/8.0/en/spatial-geojson-

functions.html#function_st-geomfromgeojson). Then use the ST_Distance() function

(https://dev.mysql.com/doc/refman/8.0/en/spatial-relation-functions-object-

shapes.html#function_st-distance) to calculate the distance between the two points.

The ST_GeomFromGeoJSON() function takes three arguments:

The location to convert. This argument is mandatory.

An integer 1-4 defining what to do in case the GeoJSON value has more than two

dimensions. 1 means reject, 2-4 means accept and ignore the higher order

dimensions. The default is 1.

The spatial reference system ID (SRID) as an unsigned integer. The default is

4326 which is the Earth. Supported values can be found in the SRS_ID column of

the information_schema.ST_SPATIAL_REFERENCE_SYSTEMS table. Support for

spatial reference systems is a MySQL 8.0 feature.

In the example the default values are used for the second and third argument, so they

could have been left off but are included to make it clear how the locations are handled.

The ST_Distance() function takes the spatial reference system of the points into

consideration, so the distance is calculated correctly (this is a MySQL 8.0 feature). The

calculated distance is for SRID = 4326 returned in meters.

Other than this, the example is straight forward. Compared to the previous example,

there are three changes:

The resulting documents are sorted by the distance in ascending order using the

sort() method.

The callback function for execute() has been to push the new document into

the docs array directly.

The logging is used doing template literals.

The output is:

0: Washington: 3928 km

1: London: 8638 km

Page 25: Developing Modern Applications with the MySQL Document ... · the examples in this workbook. If you are attending the hands-on labs session Developing Modern Applications with the

The city collection is small with just three documents and each document does not

contain much data. What if you have a large collection? In that case – as with SQL tables

– indexes can be useful.

Adding an Index

The MySQL Document Store supports indexes on the collections. This can greatly

improve the query performance for queries that otherwise would need to check a large

number of documents to return a few of them or sort/group based on a given field.

You can add an index through the collection object. You can create an index with the

createIndex() method which takes two arguments: The index name and a dictionary

defining the index. The definition of the index includes three elements:

type. The index type. Currently normal ordered (B-TREE) indexes and spatial

indexes are supported. Specify INDEX for a normal ordered index and SPATIAL

for a spatial index.

unique. Whether it is a unique index. Currently this must be set to false (which

is the default).

fields. A list of the fields to include in the index.

The fields list include a dictionary for each field to include in the index. Do note that the

order does matter. Each dictionary element for the field includes some or all of the

following elements:

field. The JSON path to the value to index. The $ to specify the root of the

document must be included.

type. Equivalent to the data type for columns in a relational table. For example

to say the value is an unsigned integer use INT UNSIGNED.

required. Whether the value must be present. Specify as a Boolean. Equivalent

to whether NOT NULL is specified.

options. For spatial columns this is an integer (1-4) specifying what to do if the

value is of dimension higher than two. Use 1 (the default) to reject such values

and 2, 3, or 4 to accept them. See

https://dev.mysql.com/doc/refman/en/spatial-geojson-

functions.html#function_st-geomfromgeojson for details.

srid. The spatial reference system for spatial values. The default is 4326 (the

usual representation of the Earth). Supported values can be found in the SRS_ID

column of the information_schema.ST_SPATIAL_REFERENCE_SYSTEMS table.

This all feels quite complex, so it is worth looking at an example. In the example you will

add an index for the location of the city:

Page 26: Developing Modern Applications with the MySQL Document ... · the examples in this workbook. If you are attending the hands-on labs session Developing Modern Applications with the

#!/usr/bin/env node

'use strict';

const mysqlx = require('@mysql/xdevapi');

const config = require('./config');

(async function() {

let session;

try {

session = await mysqlx.getSession(config.mysqlArgs);

const schema = session.getSchema(config.schema);

const city = schema.getCollection('city');

const field = {

'field': '$.Geography.Location',

'type': 'GEOJSON',

'required': true,

'options': 1,

'srid': 4326,

};

const index_def = {

'fields': [field],

'type': 'SPATIAL',

};

await city.createIndex('Location', index_def);

console.log('Index created on $.Geography.Location.');

} catch (err) {

console.error(err.message);

} finally {

session && await session.close();

}

})();

Script: createIndex.js

As usual, adding indexes can improve the performance of finding documents (whether it

is to return them, update them, or delete them), but adds overhead to keep the indexes

up to date and makes the optimizer evaluate more options for the query plan. So, it is

recommended to always test the effect of indexes for your queries and remove indexes

you no longer use.

With indexes in place, let’s move on to modifying documents.

Modifying Documents

Page 27: Developing Modern Applications with the MySQL Document ... · the examples in this workbook. If you are attending the hands-on labs session Developing Modern Applications with the

The action of modifying documents can basically be separated into two steps: finding

the document to change and applying the change. Finding the documents is essentially

the same as for a find statement. The more interesting part here is to apply the changes.

There are three methods to change documents:

addOrReplaceOne(): For upserting a document by specifying the document ID. If

there is already a document with the ID, then it is replaced, otherwise a new

document is added with the ID.

modify(): The most advanced method where you can modify one or more

documents. It can take most of the arguments known from find queries to

specify which documents to change, and additional there are methods to specify

which change to make.

replaceOne(): Similar to addOrReplaceOne() but if the document ID does not

already exist, then no change occurs.

The method that will be demonstrated here is the modify() method. As mentioned,

you need to use a sub method to specify how to make the modification of the matching

documents. The available modify methods are:

arrayAppend(): Takes an existing array element and changes it to include the

original value plus the new value(s). For example if the original array is ["One",

"Two", "Three"] and you want to append [1, "Uno"] to the element with the

value "one", the resulting array is [["One", [1, "Uno"]], "Two", "Three"].

arrayInsert(): Takes an existing array and inserts into the element position

specified. For example, if the existing document is {"fruits" = ["apple",

"orange", "watermelon"]} and the array is specified as fruits[1] with the

new element being kiwi, then the resulting document is {"fruits" =

["apple", "kiwi", "orange", "watermelon"]}.

set: If the specified element exists, update it, otherwise add the element.

patch: Takes a part of a document and replaces it with a new document part.

This supports adding, replacing, or removing parts of a document. This is a very

powerful yet simple method.

unset: Removes an element from the document.

Note: It is mandatory to set a filter condition when calling modify(). If you fail to do

this, MySQL rejects the call with the error: “A valid condition needs to be provided with

`modify()`”.

If you really want to modify all documents, specify a valid truth condition like 'true' or

similar; this also makes it clear when you look at the code later on that you meant to

match all documents.

Page 28: Developing Modern Applications with the MySQL Document ... · the examples in this workbook. If you are attending the hands-on labs session Developing Modern Applications with the

Let’s look at two examples: using set() to add/replace a given field and patch() to

add, change, and remove fields.

Using the modify().set() Method

The set() method is simple as it takes a path to a field and sets or replaces the value.

You can also use set() to update the existing value based on the current value. An

example of this is to change increase the population of the cities in the United States

with 10%:

#!/usr/bin/env node

'use strict';

const mysqlx = require('@mysql/xdevapi');

const config = require('./config');

(async function() {

let session;

let docs_before = [];

let docs_after = [];

try {

session = await mysqlx.getSession(config.mysqlArgs);

const schema = session.getSchema(config.schema);

const city = schema.getCollection('city');

// Define the parameter to use for filtering, so it can

// be reused.

const param = {'country': 'United States of America'};

// Get the before populations

const pop_stmt = city.find('Geography.Country = :country')

.fields('Name', 'Geography.State AS State',

'Demographics.Population AS Population')

.sort('Name', 'State', '_id')

.bind(param);

await pop_stmt.execute(doc => docs_before.push(doc));

// Update the populations

await session.startTransaction();

const stmt = city.modify('Geography.Country = :country')

.set('Demographics.Population',

mysqlx.expr('FLOOR(Demographics.Population * 1.10)'));

stmt.bind(param);

const result = await stmt.execute();

const affectedDocs = result.getAffectedItemsCount();

console.log(`Number of documents updated: ${affectedDocs}`);

await session.commit();

Page 29: Developing Modern Applications with the MySQL Document ... · the examples in this workbook. If you are attending the hands-on labs session Developing Modern Applications with the

// Get the populations after the update and log

await pop_stmt.execute(doc => docs_after.push(doc));

for (let i = 0; i < docs_before.length; i++) {

let name = docs_before[i]['Name'];

let state = docs_before[i]['State'];

let pop_before = docs_before[i]['Population'];

let pop_after = docs_after[i]['Population'];

console.log(`${name}, ${state}: ${pop_before} =>

${pop_after}`);

}

} catch (err) {

console.error(err.message);

} finally {

session && await session.close();

}

})();

Script: modify_set.js

There are a few new things in this example. The parameter used in bind() is stored as a

JSON object in a variable. The bind() method can take the parameter(s) in other ways

than the two arguments you have seen previously including as a JSON object. Since the

same parameter is reused for several queries, it is easier to have it defined in one place

and reuse it.

Secondly, the sort clause for the find statement includes the city name, state, and

document ID. This is to ensure the before and after queries return the documents in the

same order. It is assumed here that all affected documents already have the

$.Demographics.Population field; if that was not the case, that would have to be

taken into account. The _id field is included to ensure the ordering is deterministic in

case there are two cities with the same name and state (which is not the case here, but

it is good practice to add the primary key for these kind of cases).

The third thing is the modify().set() methods that is the topic of the example. The

filter condition is passed to the call to modify() whereas set() takes two arguments:

the JSON path to the field to change/set and the new value. Since the new population is

calculated from the old population, an expression is used to avoid first read the

population, then update one document at a time. To use an expression, the

mysqlx.expr() function is used.

Fourth, the find statement that was used to find the populations before the update is

reused to find the population afterwards as well. This shows an example of how you can

reuse statements. In this case, the bind parameter is the same, so we can just use the

statements as is, but it would also be possible to execute the statement with a different

parameter.

Finally, the updated cities are logged with the before and after populations:

Page 30: Developing Modern Applications with the MySQL Document ... · the examples in this workbook. If you are attending the hands-on labs session Developing Modern Applications with the

Number of documents updated: 2

San Francisco, California: 776733 => 854406

Washington, District of Columbia: 572059 => 629264

What if you need to make more advanced modifications to the documents, such as

removing fields, adding multiple fields, etc.? The patch() method is great for that.

Using the modify().patch() Method

The patch() method is the most powerful of the modify methods, however it is also

simple. The method takes a JSON document (which may be just part of the document

you want to modify). For each element in the provided document, the element will be

added, modified, or removed depending on whether the element exists and what the

new value is.

As an example consider the following changes to London:

Update the population to be 8 million (8000000).

Set the life expectancy to 77.7 years.

Remove the $.Geography.State field and instead add a field called

NonSovereignCountry set to England.

This can be achieved with the following example program:

#!/usr/bin/env node

'use strict';

const mysqlx = require('@mysql/xdevapi');

const config = require('./config');

(async function() {

let session;

try {

session = await mysqlx.getSession(config.mysqlArgs);

const schema = session.getSchema(config.schema);

const city = schema.getCollection('city');

// Define the parameter to use for filtering,

// so it can be reused.

const param = {'city_name': 'London'};

// Get the before document

console.log('London before patching:');

const find_stmt = city.find('Name = :city_name').bind(param);

await find_stmt.execute(

doc => console.log(JSON.stringify(doc, null, 4)));

Page 31: Developing Modern Applications with the MySQL Document ... · the examples in this workbook. If you are attending the hands-on labs session Developing Modern Applications with the

// Update the populations

const patch = {

'Demographics': {

'Population': 8000000,

'LifeExpectancy': 77.7,

},

'Geography': {

'State': null,

'NonSovereignCountry': 'England',

},

};

await session.startTransaction();

const stmt = city.modify('Name = :city_name')

.patch(patch);

const result = await stmt.bind(param).execute();

const affectedDocs = result.getAffectedItemsCount();

console.log(`\nNumber of documents updated: ${affectedDocs}`)

await session.commit();

// Get the document after the change

console.log('\nLondon after patching:')

await find_stmt.execute(

doc => console.log(JSON.stringify(doc, null, 4)));

} catch (err) {

console.error(err.message);

} finally {

session && await session.close();

}

})();

Script: modify_patch.js

The parameter used in the bind() calls is here stored in a JSON document itself to make

it easier to reuse the parameter for the statements. After logging the document for

London before the change, the patch is defined. The $.Geography.State field is set to

null which causes it to be removed. For existing fields that should be updated, the field

is included with the new value, and for new fields the field is included with the value.

So, in reality it is easy to make changes using the patch() method. The limitation is that

it is mostly suitable for updating a single document. After the document has been

patched, the new document is logged. The output of the program is (document IDs will

be different):

London before patching:

{

"_id": "00005b99c948000000000000004c",

"Name": "London",

"Capital": true,

"Geography": {

"State": "England",

Page 32: Developing Modern Applications with the MySQL Document ... · the examples in this workbook. If you are attending the hands-on labs session Developing Modern Applications with the

"Country": "United Kingdom",

"Location": {

"Type": "Point",

"Coordinates": [

-0.143,

51.501

]

}

},

"Demographics": {

"Population": 7285000

}

}

Number of documents updated: 1

London after patching:

{

"_id": "00005b99c948000000000000004c",

"Name": "London",

"Capital": true,

"Geography": {

"Country": "United Kingdom",

"Location": {

"Type": "Point",

"Coordinates": [

-0.143,

51.501

]

},

"NonSovereignCountry": "England"

},

"Demographics": {

"Population": 8000000,

"LifeExpectancy": 77.7

}

}

This concludes the examples of updating documents. The final CRUD method is to delete

documents.

Removing Documents

There are two methods to remove documents: remove()and removeOne(). The

remove() method finds documents similar to how the find() method does whereas

removeOne() finds a single document by the ID.

As an example, delete the first document sorted alphabetically by Name where the

country is the United States of America:

Page 33: Developing Modern Applications with the MySQL Document ... · the examples in this workbook. If you are attending the hands-on labs session Developing Modern Applications with the

#!/usr/bin/env node

'use strict';

const mysqlx = require('@mysql/xdevapi');

const config = require('./config');

(async function() {

let session;

try {

session = await mysqlx.getSession(config.mysqlArgs);

const schema = session.getSchema(config.schema);

const city = schema.getCollection('city');

await session.startTransaction();

const stmt = city.remove('Geography.Country = :country')

.sort('Name').limit(1);

stmt.bind('country', 'United States of America')

const result = await stmt.execute();

const affectedDocs = result.getAffectedItemsCount();

console.log(`Number of documents deleted: ${affectedDocs}`)

await session.commit();

} catch (err) {

console.error(err.message);

} finally {

session && await session.close();

}

})();

Script: remove.js

By now this should start to look familiar. The remove statement support mostly the

same methods as find and modify statements to determine which documents to

remove.

This concludes the tour of the CRUD methods. You are encouraged to keep playing with

the MySQL Document Store for the remainder of this hands-on lab as well as at home.

Please ask if you have any questions.

References

If you want to learn more about the MySQL Document Store, the following references

are useful:

X DevAPI User Guide: https://dev.mysql.com/doc/x-devapi-userguide/en/

MySQL Connector/Node.js with X DevAPI:

https://dev.mysql.com/doc/dev/connector-nodejs/8.0/

Page 34: Developing Modern Applications with the MySQL Document ... · the examples in this workbook. If you are attending the hands-on labs session Developing Modern Applications with the

MySQL Shell Documentation – JavaScript API:

https://dev.mysql.com/doc/dev/mysqlsh-api-javascript/8.0/

Using promises: https://developer.mozilla.org/en-

US/docs/Web/JavaScript/Guide/Using_promises

MySQL Shell 8.0 Manual: https://dev.mysql.com/doc/mysql-shell/8.0/en/