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.
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.
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.
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.
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:
// 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' }
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:
Now, let’s use Next.js to create an API to access ArangoDB from within our React 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; };
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.
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.
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!
Install LogRocket via npm or script tag. LogRocket.init()
must be called client-side, not
server-side
$ npm i --save logrocket // Code: import LogRocket from 'logrocket'; LogRocket.init('app/id');
// Add to your HTML: <script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script> <script>window.LogRocket && window.LogRocket.init('app/id');</script>
Would you be interested in joining LogRocket's developer community?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowSOLID principles help us keep code flexible. In this article, we’ll examine all of those principles and their implementation using JavaScript.
JavaScript’s Date API has many limitations. Explore alternative libraries like Moment.js, date-fns, and the new Temporal API.
Explore use cases for using npm vs. npx such as long-term dependency management or temporary tasks and running packages on the fly.
Validating and auditing AI-generated code reduces code errors and ensures that code is compliant.