# JavaScript client guide

Learn how to create a JavaScript application that connects to the 
Memgraph database and executes simple queries.

Running queries directly from a web browser is **not 
recommended** because of additional requirements and possible 
performance issues. In other words, we encourage you to use 
server-side libraries and clients for top performance whenever 
possible.

## Quickstart

With this JavaScript quickstart guide learn the first steps 
of connecting to Memgraph and executing simple queries.

These instructions will guide you through your first steps of 
connecting to a running Memgraph database instance and visualizing 
your data using JavaScript.

### Run Memgraph 

If you're new to Memgraph or you're in a developing stage, we
recommend using the Memgraph Platform. Besides the database, it also
includes all the tools you might need to analyze your data, such as command-line
interface [mgconsole](https://memgraph.com/docs/getting-started/cli), web interface [Memgraph
Lab](https://memgraph.com/docs/data-visualization) and a complete set of algorithms within a
[MAGE](https://memgraph.com/docs/advanced-algorithms) library.

Ensure [Docker](https://docs.docker.com/engine/install/) is running in the
background. Depending on your operating system, execute the appropriate command
in the console:

**For Linux and macOS:**

```bash
curl -sSf "https://install.memgraph.com" | sh
```

**For Windows:**

```bash
iwr https://install.memgraph.com/windows -useb | iex
```

The command above will start [Memgraph
Platform](https://memgraph.com/docs/getting-started/install-memgraph/docker#install-memgraph-platform),
which includes [Memgraph
database](https://memgraph.com/docs/getting-started/install-memgraph/docker#other-available-docker-images),
[Memgraph Lab](https://memgraph.com/docs/data-visualization#quick-start) and [Memgraph
MAGE](https://memgraph.com/docs/advanced-algorithms#quick-start). Memgraph uses Bolt protocol to
communicate with the client using the exposed 7687 port. Memgraph Lab is a web
application you can use to visualize the data. It's accessible at
[http://localhost:3000](http://localhost:3000) if Memgraph Platform is running
correctly. The 7444 port enables Memgraph Lab to access and preview the logs,
which is why both of these ports need to be exposed. 

For more information visit the getting started guide on [how to run Memgraph
with Docker](https://memgraph.com/docs/getting-started/install-memgraph/docker).

### Install JavaScript Driver

To create the following JavaScript application, you first need
to install the JavaScript Driver.

Run the following *npm* command to install the [Neo4j JavaScript 
Driver](https://www.npmjs.com/package/neo4j-driver):

```
npm i neo4j-driver
```

> **Info**
>
> The Driver requires `npm` and any LTS version of node.js.

### Set up your script

Create a new directory for your application and position
yourself in it:

```
mkdir myApp
cd myApp
```

Next, create an `example.js` file
and add the following code:

```js
(async () => {
    var db = require('neo4j-driver');
  
    const URI = 'bolt://localhost:7687';
    const USER = '';
    const PASSWORD = '';
    let driver;
  
    try {
      driver = db.driver(URI, db.auth.basic(USER, PASSWORD));
      const serverInfo = await driver.getServerInfo();
      console.log('Connection established');
      console.log(serverInfo);

      const session = driver.session();

      try {
        // Clear the database
        await session.run("MATCH (n) DETACH DELETE n;");
        console.log("Database cleared.");

        // Create a user in the database
        await session.run("CREATE (:Person {name: 'Alice', age: 22});");
        console.log("Record created.");

        // Get all of the nodes
        const result = await session.run("MATCH (n) RETURN n;");
        console.log("Record matched.");

        const mark = result.records[0].get("n");
        const label = mark.labels[0];
        const name = mark.properties["name"];
        const age = mark.properties["age"];

        if (label != "Person" || name != "Alice" || age != 22) {
          console.error("Data doesn't match.");
        }

        console.log("Label: " + label);
        console.log("Name: " + name);
        console.log("Age: " + age);
      } catch (error) {
        console.error(error);
      } finally {
        session.close();
      }

      driver.close();

    } catch (err) {
      console.log(`Connection error\n${err}\nCause: ${err.cause}`);
      await driver.close();
      return;
    }
  
    await driver.close();
  })();
```

### Run the script

After running your script with node `example.js`,
you should receive the output in your terminal similar to this: 

```
Database cleared.
Record created.
Record matched.
Label: Person
Name: Alice
Age: 22
```
The output above indicates that you are connected to the database and ready to visualize data
you created.

### Visualize the data

To visualize data created with the script, head over to 
`localhost:3000` or the desktop version of Memgraph Lab and run the following query in the *Query Execution* tab: 

```MATCH (n) RETURN n;``` 

The query visualizes the created node and by clicking on it you can 
explore its properties.

![javascript-quick-start](https://memgraph.com/docs/pages/client-libraries/javascript/javascript-quick-start.png) 

### Next steps

You now have the basic JavaScript application that connects
you to Memgraph and you are ready to start building more 
complex queries on top of it. Happy querying!

## JavaScript client usage and examples

Once we covered the basic concept, we can explore more advanced usages 
of JavaScript library, explain code snippets and provide more examples.

### Database connection

Once the database is running, you should be able to connect to it 
in one of two ways:

- [Connect without authentication (default)](https://memgraph.com/docs/client-libraries/javascript#connect-without-authentication-default)
- [Connect with authentication](https://memgraph.com/docs/client-libraries/javascript#connect-with-authentication)
 
#### Connect without authentication (default)

By default, the Memgraph database is running without authentication, 
which means that you can connect to the database without providing any 
credentials (username and password). If you're running Memgraph locally, 
the URI should be similar to `bolt://localhost:7687`, and if you are running 
Memgraph on a remote server, replace `localhost` with the appropriate IP address. 
If you ran Memgraph on a port different than 7687, do not forget to update that 
in the URI too.

By default, you can set username and password argument as empty strings. 
This means that you are connecting without authentication.

To connect a JavaScript client to the Memgraph database without authentication, 
you can use the following code snippet:

```js
(async () => {
    var db = require('neo4j-driver');
  
    const URI = 'bolt://localhost:7687';
    const USER = '';
    const PASSWORD = '';
    let driver;
  
    try {
      driver = db.driver(URI, db.auth.basic(USER, PASSWORD));
      const serverInfo = await driver.getServerInfo();
      console.log('You are now connected to Memgraph!');
      console.log(serverInfo);

      driver.close();

    } catch (err) {
      console.log(`Connection error\n${err}\nCause: ${err.cause}`);
      await driver.close();
      return;
    }
  
    await driver.close();
  })();
```

#### Connect with authentication

In order to set up authentication in Memgraph, you need to create a user 
with a `username` and `password`. In Memgraph you can set a username and 
password by executing the following query:

```CREATE USER `memgraph` IDENTIFIED BY 'password';```

Then, you can connect to the database with the following snippet:

```js
(async () => {
    var db = require('neo4j-driver');
  
    const URI = 'bolt://localhost:7687';
    const USER = 'memgraph';
    const PASSWORD = 'password';
    let driver;
  
    try {
      driver = db.driver(URI, db.auth.basic(USER, PASSWORD));
      const serverInfo = await driver.getServerInfo();
      console.log('You are now connected to Memgraph!');
      console.log(serverInfo);

      driver.close();

    } catch (err) {
      console.log(`Connection error\n${err}\nCause: ${err.cause}`);
      await driver.close();
      return;
    }
  
    await driver.close();
  })();
```

For more details on how to create user with credentials and set authentication, 
visit the [Memgraph authentication guide](https://memgraph.com/docs/configuration/security#creating-user).

### Query the database

After connecting your driver to Memgraph, you can start running queries. 
The simplest way to execute Cypher queries is by using the `session.run` method.
You can pass a Cypher query as a string to `session.run` and it returns a result 
object that you can use to retrieve data from the query response.

#### Run a create query

The following code snippet contains a query that will create a node inside the database:

```js
const session = driver.session();
try{
  // Create a user in the database
  await session.run("CREATE (:Person {name: 'Alice', age: 22});");
  console.log("Record created.");
}
catch (error) {
  console.error(error);
} finally {
  session.close();
}
```

The code above creates a session that takes a Cypher query as an argument and 
executes it to create a new node in the database. Next, it handles any potential errors 
that may occur during the execution. It follows best practices by closing the session 
the finally block to clean up resources and maintain proper database connection management.

#### Run a read query

The following code snippet contains a query that will read and retrieve data drom the database:

```js
const session = driver.session();
try{
  result = await session.executeRead(async tx => { 
  // Use the method `Transaction.run()` to run queries
  return await tx.run(`  
    MATCH (p:Person) WHERE p.name = 'Alice'
    RETURN p.name as name ORDER BY name
    `
  )
  })
  for(let record of result.records) {  
    console.log(record.get('name'))
  }
}
catch (error) {
  console.error(error);
} finally {
  session.close();
}
```

### Process the results

Processing results from the database is important since we do not want 
to lose any data during conversions. To properly read results and serve 
them back to the JavaScript application, they need to be cast into proper types.

Depending on the type of request made, you can receive different results, 
Nodes, Relationships, Paths etc. Let's go over a few basic examples of 
how to handle different types and access properties of the returned results.

#### Process the Node result

In order to process the result, you need to read them first. You can do that 
with the following code snippet:

```js
const session = driver.session();
try{
  result = await session.executeRead(async tx => { 
    // Use the method `Transaction.run()` to run queries
    return await tx.run(`  
    MATCH (n:Technology {name: 'Memgraph'}) 
    RETURN n
    `)
  })
  // Process the result records
  for(let record of result.records) { 
    console.log(record.get('n'))
  }
}
catch (error) {
  console.error(error);
} finally {
  session.close();
}
```

The provided code snippet matches the node with the property name being Memgraph, 
runs a for loop through all the retrieved results and processes them. Assuming 
that the matched node has properties `name`, `id` and `description`, the output 
could be similar to this:

```
Node {
  identity: Integer { low: 106, high: 0 },
  labels: [ 'Technology' ],
  properties: {
    description: 'Fastest graph DB in the world!',
    id: '1',
    name: 'Memgraph'
  },
  elementId: '106'
}
```

#### Process the Relationship result

You can also receive a relationship information from a query. For example:

```js
const session = driver.session();
try{
  // Create a relationship between two nodes, developer and technology
  await session.executeRead(async tx => { 
    return await tx.run(`  
    CREATE (d:Developer {name: 'John Doe'})-[:USES {id:99}]->(t:Technology {id: 1, name:'Memgraph', description: 'Fastest graph DB in the world!'})
    `)
  })
  // Read a relationship between two nodes, developer and technology
  result = await session.executeRead(async tx => { 
    return await tx.run(`  
    MATCH (d:Developer)-[r:USES]->(t:Technology) RETURN r
    `)
  })
  
  // Process the results
  for(let record of result.records) { 
    console.log(record.get('r'))
  }
}
catch (error) {
  console.error(error);
} finally {
  session.close();
}
```
With the `console.log(record.get('r'))` line of code, you are able
to get the all of the information about certain relationship as your
output. If you're only interested in, for example,  relationship type, 
ID of the start node and ID of the end node, you can replace that line of 
code with this:

```
console.log("Relationship type: ", record.get('r').type)
console.log("Start node ID: ", record.get('r').startNodeElementId)
console.log("End node ID: ", record.get('r').endNodeElementId)
```
and receive an output similar to this:

```
Relationship type:  USES
Start node ID:  <ID>
End node ID:  <ID>
```

#### Process the Path result

You can receive path from the database, using the following code snippet:

```js
const session = driver.session();
try{
  // Create a relationship between two nodes, developer and technology
  result = await session.executeRead(async tx => { 
    return await tx.run(`  
    MATCH p=(d:Developer)-[r:USES]->(t:Technology) RETURN p
    `)
  })
  
  // Process the results
  for(let record of result.records) { 
    console.log(record.get('p'))
  }
}
catch (error) {
  console.error(error);
} finally {
  session.close();
}
```

Path will contain [Nodes](#process-the-node-result) and 
[Relationships](#process-the-relationship-result), that can be accessed in 
the same way as in the previous examples, by casting them to the relevant type.

### Transactions management

When querying the database, the driver automatically creates a transaction. 
A transaction is a unit of work that is either *committed* in its entirety 
or *rolled back* on failure. For more advanced use-cases, the driver provides 
functions to take full control over the **transaction lifecycle**.

On the driver side, if a transaction fails because of a transient error, the transaction is retried automatically. 
The transient error will occur during write conflicts or network failures. The driver will retry the transaction function with an exponentially increasing delay.

#### Automatic transactions

When you execute a query using `session.run`, the driver automatically creates 
a transaction to encapsulate the Cypher queries you're executing. This automatic 
transaction management simplifies the process of working with transactions. 
That method should be used when transaction control is unnecessary. 

> **Info**
>
> As of Memgraph version 3.2, queries are categorized as **read** or **write** and the corresponding storage access is taken. This allows for better query parallelization and higher throughput.
> For single query automatic transaction, no user input is required, Memgraph will deduce the access type needed at parse-time. See [transaction accessor misalignment](https://memgraph.com/docs/fundamentals/transactions#transaction-accessor-misalignment) for more details.

#### Manual transactions

Before running a transaction, you need to obtain a *session*. Sessions act 
as concrete query channels between the driver and the server, and ensure 
causal consistency is enforced. 

`session = driver.session()`

> **Info**
>
> Sessions are not thread-safe, which means you can share the main Driver object across
> threads, but make sure each thread creates its own sessions.

##### Managed transactions

A transaction can contain any number of queries. As Memgraph is 
**ACID compliant**, queries within a transaction will either be 
executed as a whole or not at all. 
You cannot get a part of the transaction succeeding and another 
failing. Use transactions to group together related queries which 
work together to achieve a single logical database operation.

A **managed transaction** is created using the `session.executeRead()` 
and `session.executeWrite()` methods, depending on whether you 
want to retrieve data from the database or alter it. Both methods 
take a transaction function callback, which is responsible for 
carrying out the queries and processing the results. Here's an 
example of a managed transaction using the `session.executeRead()` 
method.

```js
try {
  let session, result
  // Create a session
  session = driver.session()

  // The `.executeRead()` method is the entry point into a transaction  
  result = await session.executeRead(async tx => { 
    // Use the method `Transaction.run()` to run queries
    return await tx.run(`  
      MATCH (p:Person) WHERE p.name = 'Alice'
      RETURN p.name as name ORDER BY name
      `
    )
  })
  // Process the result records
  for(let record of result.records) {  
    console.log(record.get('name'))
  }
} finally {
  // Remember to close session when done
  session.close()
}

```

Within a transaction function, a return statement results in the transaction 
being committed, while the transaction is **automatically rolled back** if 
an exception is raised.

Because of this, it is impossible to know how many time the transaction is going to be executed, so transaction functions should produce the same results even when run several times. This means you shouldn't, for example, 
 edit nor
rely on globals. Note that although transaction functions might be 
executed multiple times, the queries inside it will always run only once.

> **Info**
>
> As of Memgraph version 3.2, queries are categorized as **read** or **write** and the corresponding storage access is taken. This allows for better query parallelization and higher throughput.
> Using `executeRead` and `executeWrite` informs Memgraph what type of access is required for the transaction.
> An exception will be thrown if the user tries to execute a write query inside a read transaction. See [transaction accessor misalignment](https://memgraph.com/docs/fundamentals/transactions#transaction-accessor-misalignment) for more details.

##### Explicit transactions

You can achieve full control over transactions by manually starting them using the 
`session.beginTransaction()` method. You run queries inside an explicit transaction 
with the `Transaction.run()` method, as you do in transaction functions.

> **Info**
>
> As of Memgraph version 3.2, queries are categorized as **read** or **write** and the corresponding storage access is taken. This allows for better query parallelization and higher throughput.
> Explicit transactions can cover a number of individual queries, but storage access is given at the start. For best performance, the user needs to declare whether the transaction should use read or write access.
> This can be done by setting the session's `defaultAccessMode` to `'READ'` or `'WRITE'`. This will, in turn, set the access mode of a transaction created via the `begin_transaction` function. Note that `executeRead` and `executeWrite` will override the session's default access.

```js
let session = driver.session({ database: 'neo4j', defaultAccessMode: 'READ' })
let transaction = await session.beginTransaction()

// await transaction.run('<QUERY 1>')
// await transaction.run('<QUERY 2>')
// ...

await transaction.close()
await session.close()
```

The behavior and lifetime of an explicit transaction is controlled using the 
`Transaction.commit()`, `Transaction.rollback()`, or `Transaction.close()` methods .

Explicit transactions are useful when applications need to distribute 
Cypher execution across multiple functions for the same transaction or 
run multiple queries within a single transaction but 
without the automatic retries provided by managed transactions.

> **Info**
>
> If you encounter serialization errors while using JavaScript client, we recommend
> referring to our [Serialization errors](https://memgraph.com/docs/help-center/errors/serialization) page
> for detailed guidance on troubleshooting and best practices.
