Alex Merced I am a developer, educator, and founder of devNursery.com.

Using ArangoDB with React and Next.js

6 min read 1740

ArangoDB React Nextjs

Nowadays, developers can handle the complex data types used in modern applications without having to integrate multiple databases; multi-model databases combine the best of different database paradigms, like graph, document, and relational databases into a single program.

In this tutorial, we’ll explore ArangoDB, a multi-model, open source database that provides flexible data models for documents, graphs, and key-values. We’ll build our simple database application with React and Next.js.

Like its contenders, MongoDB, Fauna, DGraph, and Neo4j, ArangoDB uses a cloud-hosted database service, Oasis, which makes it easy to build and scale your application.

Getting Started with ArangoDB

First, sign up for a new Oasis account on cloud.arangodb.com. Select project on the menu to create a new ArangoDB project; to stay within the free tier of ArangoDB, be sure to stick with the OneShard basic service.

Next, choose a name for your project and select your cloud provider and region. You’ll need to wait a few minutes while your database is bootstrapped.

To navigate to your web dashboard, click on the icon next to your database’s URL. Log in using room as the username and your dashboard’s password. Under users, create a new user. Finally, go to databases and create a test database.

Getting familiar with Arango Query Language

To familiarize ourselves with Arango Query Language (AQL), let’s create a new example collection called cheese. Head to the queries section and run the code below to insert data into the cheese collection:

INSERT {name: "American"}
IN cheese

Go ahead and add a few items to the cheese collection. To get items from the cheese collection, run the query below:

FOR c IN cheese
    RETURN c

The ArangoDB syntax is pretty self-explanatory, and you can see additional query examples in the query documentation.

ArangoDB Node.js drivers

Before adding ArangoDB to our React and Next.js project, let’s review how drivers work in Node.js. At the time of writing, I’m using Node.js v16.10.

We made a custom demo for .
No really. Click here to check it out.

Create a new folder called arangotest. Inside, run the command below to create a new project:

npm init -y

Install the ArangoDB JavaScript Driver as follows:

npm install arangojs

Now, create an index.js file. Establish the database connection by adding the code below, however, be sure it reflects your unique database connection string:

const { Database, aql } = require("arangojs");

// establish database connection
const db = new Database({
  url: "https://XXXXXXXXXX.arangodb.cloud:8529/",
  databaseName: "XXXXXX",
  auth: { username: "XXXXXXX", password: "XXXXXX" },
});

Now, we’ll define a function that either creates a new collection in our database or prevents an error from occurring if the collection already exists:

The function below:

  • Receives a collection name as an argument
  • Gets a list of all collections currently in the database
  • Determines if the desired collection already exists
  • Creates the collection if it didn’t already exist
  • Returns the collection
// function to get collection or create it if it doesn't exist
    const getCollection = async (cName) => {
      // get list of collections in database
      const collections = await db.collections();
// check if collection exists, if so return collection, if not, create it if (collections.includes(cName)) { return await db.collection(cName); } else { return db.createCollection(cName); } };

Let’s try adding a new item, cat, to our collection. The function below runs getCollection, ensuring that the collection exists. It also runs a query that passes the name argument through interpolation. The AQL tag handles and protects the function from injection attacks:

// create a new cat
const createCat = async (name) => {
    // make sure cat collection exists
    await getCollection("cats")
    // query to insert a cat
    await db.query(aql`INSERT {name: ${name}} IN cats`)
}

Now, let’s run a function that will query the results. AQL queries return asynchronous ArrayCursor objects. To get our results in an array, we’ll have to loop over the query cursor and push the results in an array.

The function below checks if the collection exists, creates an array to store results, queries for cats, loops through the arrayCursor, pushes each cat item into the array, and returns the array of cats:

const getCats = async () => {
    // make sure cat collection exists
    await getCollection("cats")
    // declare array to hold cats
    let result = []
    // query for cats
    const results = await db.query(aql`FOR c IN cats RETURN c`)
    // loop through array cursor and push results in array
    for await (cat of results){
        result.push(cat)
    }
    // log results
    console.log(result)
    // return the list of cats
    return result
}

The complete code for the project looks like the following code block:

const { Database, aql } = require("arangojs");

// establish database connection
const db = new Database({
  url: "https://xxxxxxxxx.arangodb.cloud:8529/",
  databaseName: "xxxxxx",
  auth: { username: "xxxxxxx", password: "xxxxxxx" },
});

// function to get collection or create it if it doesn't exist
const getCollection = async (cName) => {
  // get list of collections in database
  const collections = await db.collections();

  // check if collection exists, if so return collection, if not, create it
  if (collections.find((c) => c._name === cName)) {
    return await db.collection(cName);
  } else {
    return db.createCollection(cName);
  }
};

// create a new cat
const createCat = async (name) => {
    // make sure cat collection exists
    await getCollection("cats")
    // query to insert a cat
    await db.query(aql`INSERT {name: ${name}} IN cats`)
}

// query cats

const getCats = async () => {
    // make sure cat collection exists
    await getCollection("cats")
    // declare array to hold cats
    let result = []
    // query for cats
    const results = await db.query(aql`FOR c IN cats RETURN c`)
    // loop through array cursor and push results in array
    for await (cat of results){
        result.push(cat)
    }
    // log results
    console.log(result)
    // return the list of cats
    return result
}

createCat("Miles")

getCats()

After you run this code a few times, you’ll see that each item has several properties that we can use as a unique identifier:

  {
    _key: '10012443',
    _id: 'cats/10012443',
    _rev: '_dEUBD1---_',
    name: 'Miles'
  }

Using ArangoDB in your React application

You want to avoid exposing your database credentials on your application’s frontend. To do so, we have a couple of options that will still let you use your favorite frontend framework.

For one, you can create an API with your favorite Node.js framework, like Express, Koa.js, Fastify, Sails.js, Loopback, FoalTS, or NestJS. Alternately, you can use serverless functions, which is easy with Vercel or Netlify. Lastly, you can use whatever isomorphic framework pairs with the frontend of your choice:

  • React/ Next.js
  • Vue/ Nuxt.js
  • Svelte/ SvelteKit
  • Angular/ Angular Universal

Now, let’s use Next.js to create an API to access ArangoDB from within our React application.

Set up your Next.js application

Generate a new Next.js application by running the command below in your terminal:

npm init next-app

Name the project arangoreact. Once the project is done generating, CD into the folder and install arangojs:

npm install arangojs

Create a folder called utils; inside, create a file called db.js. Let’s wrap our connection code in its own function so that we can connect as needed:

const { Database, aql } = require("arangojs");

const getConnection = () => {
  // establish database connection
  return new Database({
    url: "https://5e5b9f99f7e1.arangodb.cloud:8529/",
    databaseName: "test",
    auth: { username: "testuser", password: "test" },
  });
};

Now, we’ll copy over our getCollection function and modify it so that it receives the connection as an argument:

// function to get collection or create it if it doesn't exist
const getCollection = async (cName, db) => {
  // get list of collections in database
  const collections = await db.collections();

  // check if collection exists, if so return collection, if not, create it
  if (collections.find((c) => c._name === cName)) {
    return await db.collection(cName);
  } else {
    return db.createCollection(cName);
  }
};

Next, we’ll get our function to query cats, then export it so we can use it in an API route. Notice that we updated the function to establish the connection inside of it:

// query cats

export const getCats = async () => {
  // make connection
  const db = getConnection()
  // make sure cat collection exists
  await getCollection("cats", db);
  // declare array to hold cats
  let result = [];
  // query for cats
  const results = await db.query(aql`FOR c IN cats RETURN c`);
  // loop through array cursor and push results in array
  for await (let cat of results) {
    result.push(cat);
  }
  // log results
  console.log(result);
  // return the list of cats
  return result;
};

Creating our API route in Next.js

Create a file in pages/api called cats.js:

import { getCats } from "../../utils/db";

export default async function (req, res){

    const cats = await getCats()
    console.log(cats)
    res.json(cats)

}

Now, you should be able to turn on the Next.js dev server npm run dev, then test the API by making a GET request to localhost:3000/api/cats from a platform like Postman or Insomnia.

Getting data from a React component

At this point, the data is delivered through a standard API endpoint. We’ll use the standard practice of getting data from an API.

First, we’ll declare state to hold the API data with the useState Hook. Next, we’ll declare a function to request the data with fetch and update the state. We’ll call the function within the useEffect Hook so that it only happens once when the page loads.

Add the code below in pages/index.js:

import {useState, useEffect} from "react"

export default function index (){

  // create the state
  const [cats, setCats] = useState([])

  // function to request cats and update state
  const fetchCats = async () => {
    const response = await fetch("/api/cats")
    const data = await response.json()
    setCats(data)
  }

  // call the function on page load with useEffect
  useEffect(() => fetchCats(), [])

  // return JSX using cats data

  return <div>
    {cats.map(cat => (
      <ul>
        {Object.keys(cat).map(key => (
          <li>{key}: {cat[key]}</li>
        ))}
      </ul>
    ))}
  </div>
}

Now, if you visit localhost:3000, you’ll see all of our cats listed on the page. We have just successfully pulled data from our ArangoDB database into our React app.

Conclusion

Multi-model databases are a game changer for improving and organizing complex databases. In this tutorial, we explored ArangoDB with React and Next.js. First, we became familiar with Arango Query Language with a simple example, then we learned how to work from an online ArangoDB dashboard and Node.js drivers.

ArangoDB is a great choice for handling extensive, complicated databases in your React application. Fairly straightforward to use, it offers a simple solution to mapping data by combining the functionalities of graph, document, and relational databases. I hope you enjoyed this tutorial!

Full visibility into production React apps

Debugging React applications can be difficult, especially when users experience issues that are hard to reproduce. If you’re interested in monitoring and tracking Redux state, automatically surfacing JavaScript errors, and tracking slow network requests and component load time, try LogRocket.

LogRocket is like a DVR for web apps, recording literally everything that happens on your React app. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred. LogRocket also monitors your app's performance, reporting with metrics like client CPU load, client memory usage, and more.

The LogRocket Redux middleware package adds an extra layer of visibility into your user sessions. LogRocket logs all actions and state from your Redux stores.

Modernize how you debug your React apps — .

Alex Merced I am a developer, educator, and founder of devNursery.com.

Leave a Reply