Part 9: Set up the Node.js server to handle Elasticsearch requests

lisahjung

Lisa Jung

Posted on September 7, 2022

Part 9: Set up the Node.js server to handle Elasticsearch requests

Table of Content | Read Next: Part 10 - Visualize data with Kibana Lens

Review

In part 8, we have created the client side of the app.

Image description

Using the client, the user can search for earthquakes that match the specified criteria(type, magnitude, location, date range).

We have set up our client to capture the user input and send the input to the server.

In this blog, we will set up our server to:

  • receive the user input from the client and pass the user input into a Elasticsearch request
  • send the request to Elasticsearch and receive relevant documents from Elasticsearch
  • send the received documents to the client so the search results could be displayed to the user

Resources

Would you rather watch a video to learn this content? Click on the link below!

Want the code covered in this blog? Click on the link below to access it!

Set up the server to handle Elasticsearch request

Using your code editor, open the earthquake_app directory. Within the server directory, locate the server.js file.

In server.js, replace the existing code with the following code.



//in server/server.js'
const { Client } = require('@elastic/elasticsearch');
const client = require('./elasticsearch/client');
const express = require('express');
const cors = require('cors');

const app = express();

const data = require('./data_management/retrieve_and_ingest_data');

app.use('/ingest_data', data);

app.use(cors());

app.get('/results', (req, res) => {
  const passedType = req.query.type;
  const passedMag = req.query.mag;
  const passedLocation = req.query.location;
  const passedDateRange = req.query.dateRange;
  const passedSortOption = req.query.sortOption;

  async function sendESRequest() {
    const body = await client.search({
      index: 'earthquakes',
      body: {
        sort: [
          {
            mag: {
              order: passedSortOption,
            },
          },
        ],
        size: 300,
        query: {
          bool: {
            filter: [
              {
                term: { type: passedType },
              },
              {
                range: {
                  mag: {
                    gte: passedMag,
                  },
                },
              },
              {
                match: { place: passedLocation },
              },
              // for those who use prettier, make sure there is no whitespace.
              {
                range: {
                  '@timestamp': {
                    gte: `now-${passedDateRange}d/d`,
                    lt: 'now/d',
                  },
                },
              },
            ],
          },
        },
      },
    });
    res.json(body.hits.hits);
  }
  sendESRequest();
});

const PORT = process.env.PORT || 3001;

app.listen(PORT, () => console.group(`Server started on ${PORT}`));


Enter fullscreen mode Exit fullscreen mode

Let's go over the newly added code!

Heads up!

For reference purposes only, I have included screenshots of code that I will be explaining.

If you need to copy and paste the code, please refer to the code snippet above or the GitHub repo for part 9.

Image description

Line 4
We import cors dependency we have installed in part 2.

We will be using cors to allow our server(http://localhost:3000) and client(http://localhost:3001) of different origin to exchange information without encountering a CORS error.

Line 12
We use app.use(cors()) to enable all CORS requests.

Lines 14-66
We create an endpoint called /results to handle HTTP requests from the client.

Review from part 8

Using the client, the user can search for earthquakes based on the criteria they select(type, magnitude, location, and date range).

Image description

The user can also sort the results by descending or ascending order of magnitude.

When the user specifies the criteria and clicks on the search button, the user input is captured and sent to the server.

Lines 15-19 create constants for the user input received from the client(type, mag, location, dateRange and sortOption).

Image description

Lines 21-64
We define the sendESRequest() function. This function is designed to send a search request to Elasticsearch.

This search request retrieves earthquake documents that match the user's selected criteria(type, magnitude, location, and time range).

Line 22
Image description

We create a constant called body and set it equal to the client.search() method.

Within the client.search() method, we leave instructions for Elasticsearch on what documents we wish to retrieve.

Line 23
We instruct Elasticsearch to search against the index earthquakes.

Line 24
In the request body(lines 24-61), we include the search criteria.

Sort by Magnitude (Lines 25-31)
Using the client, a user can sort the search results by descending or ascending order of magnitude.

Image description

Image description

To accomplish this, we add the sort parameter(line 25) in the request body. We specify that the search results must be ordered by the value of the field mag(line 27).

The sorting order(desc or asc) is determined by the user input passedSortOption(line 28).

Line 32
We instruct Elasticsearch to retrieve up to 300 matching documents.

Lines 33-60
Our app is designed to retrieve earthquake documents that match the user's chosen criteria(type, mag, location, and dateRange).

The documents must match all four of the user's criteria to be considered as a hit(search result). To retrieve such documents, we will write four queries and combine them into one request.

The bool query becomes super handy when we are trying to accomplish such a task!

We covered this query in season 1 of Mini Beginner's Crash Course to Elasticsearch and Kibana. Check out these videos(part 1 & part 2) if you need a refresher!

In a bool query(lines 33-60), we use a combination of one or more clauses to narrow down our search results.

Image description

In our case, documents in the earthquakes index either match or do not match user input(yes or no).

Therefore, we use the filter clause(line 35) to retrieve documents that match the user's input of type, magnitude, location, and date range.

Quake Type (lines 36-38)
Using our client, a user can select the type of quake from the drop down menu.

Image description

When a user selects an option, the user input is sent to the server and saved as a constant called passedType(line 15).

Image description

passedType contains the option value the user has selected from the dropdown menu(earthquake, quarry blast, ice quake, or explosion).

Since we are looking for a specific term(earthquake, quarry blast, ice quake, or explosion) within the document, we use the term query.

Image description

We instruct Elasticsearch to look for the term contained in the constant passedType in the field type(line 37).

Magnitude (lines 39-45)
Using our client, a user can select the level of magnitude from the drop down menu.

Image description

These options allow the user to search for earthquakes with magnitudes that is greater than or equal to 2.5, 5.5, 6.1, 7, and 8.

When a user selects an option, the user input is sent to the server and saved as a constant called passedMag(line 16).

Image description

passedMag contains the value of the chosen option (2.5, 5.5, 6.1, 7, or 8).

Since we are looking for documents that reflect a range of magnitudes, we use the range query for this task.

Image description

We run the range query(line 40) on the field mag(line 41). We look for documents that contain values that are greater than or equal(gte) to the value of passedMag(line 42).

Location (lines 46-48)
Using our client, a user can type in the location in which they want to search for earthquakes.

Image description

The user input is sent to the server and saved as a constant called passedLocation(line 17).

Image description

passedLocation contains whatever text the user has typed in.

Image description

To search the field place for the typed user input, full text search should be performed. Therefore, we use the match query to look for passedLocation in the field place(line 47).

Date Range (lines 50-57)
Using our client, a user can choose the date range of earthquake occurrence.

Image description

This user input is sent to the server and saved as a constant called passedDateRange(line 18).

Image description

passedDateRange contains the date range option the user has selected(past 7 days, past 14 days, past 21 days, and past 30 days).

Since we are looking for documents that reflect a range of dates, we need to use the range query for this task.

Image description

We run the range query(line 51) on the field @timestamp(line 52).

Lines 54-55
We instruct Elasticsearch to look for documents whose timestamp falls within the past x days that the user has specified.

At first glance, these lines of code may look complicated so let's break this down.

The term gte in line 53 stands for "greater than or equal to".

The term lt in line 54 stands for "less than".

We use these terms to specify the date range that a document must fall into to be considered as a search result.

The term now/d represents the current timestamp(the time when your request reaches Elasticsearch).

Therefore, lines 54-55 are telling Elasticsearch to find the documents that fall between now and now minus PassedDateRange which is the number of days specified by the user.

As a result, Elasticsearch will look for documents whose timestamp falls within the past x days that the user has specified.

Line 63
Image description

When the request is sent to Elasticsearch, Elasticsearch will retrieve relevant documents and send the documents to the server.

Once the documents have been received by the server, the server is instructed to send the documents to the client so it can display the search results.

Line 65
We call the sendESRequest() function so it would execute when the server receives an http request to the /results endpoint.

Final product

Now the moment we have all been waiting for! Let's check out what we have built!

Go back to your terminal.

cd into the earthquake_app directory. Start the server by executing the following command.



//in terminal within the earthquake_app directory
npm start


Enter fullscreen mode Exit fullscreen mode

Screenshot of the terminal:

Image description

Add a new tab to your terminal.

cd into the earthquake directory then into the client directory. Start the client by executing the following command.



//in terminal earthquake_app/client
npm start


Enter fullscreen mode Exit fullscreen mode

Screenshot of the terminal:

Image description

Image description

It should automatically display the home page of the app(http://localhost:3000)!

Image description

In the browser, specify the criteria of earthquakes you are looking for and hit the search button.

If Elasticsearch contains the documents you seek, you will see the search results displayed in the form of cards.

You should see that the search results are sorted by the sorting order you have specified!

Image description

If Elasticsearch does not have the documents you seek, you will see the following message displayed on the page.
Image description

There you have it! You have successfully created a full stack JavaScript app that can search for earthquake data stored in Elasticsearch!

Next, we are going to explore our data even further.

Move on to Part 10 to visualize data with Kibana Lens!

💖 💪 🙅 🚩
lisahjung
Lisa Jung

Posted on September 7, 2022

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related