Sample Application

Couchbase Travel is a sample web application that demonstrates how to interact with the Couchbase query service via the SDKs

Each SDK comes with its own implementation of the backend for the application.
You can download the complete source code and then build and run the app.
While the app runs, you can view the log of N1QL queries that it sends.
The documentation for the travel app illustrates the data model and walks through the N1QL queries used to select flights.

The travel app front-end is the same in each SDK implementation and incorporates the following frameworks:

Please refer to the travel-app documentation of your SDK of choice for specifics for that particular SDK, like backend dependencies, source-code checkout and running instructions.

The application allows users to find flights by entering airports and travel dates.
For the airport entries, the app uses a N1QL query bound to an Angular type ahead directive to suggest airport names based on the first few letters entered.

Generic set up

A local Couchbase 4.5 installation (make sure that the travel-sample bucket has been loaded and that there is, at least, one node with data, query, index and search services in the cluster

That’s it!

To start with, it’s easiest if you run Couchbase Server and the travel sample app on the same machine.
It’s not required to run your development environment this way, and advanced "MDS" configurations are supported.
It’s just easier to start a development environment with components running locally.

Download Couchbase Server 4.5and install it.
As you follow the download instructions and setup wizard, make sure you keep all the services (data, query, and index) selected.
Make sure also to install the sample bucket named travel-sample (introduced in CB 4.0) because it contains the data used in this tutorial.

If you already have Couchbase Server installed but did not install the travel-sample bucket, open the Couchbase Web Console and select SettingsSample Buckets.
Select the travel-sample checkbox, and then click Create.
A notification box in the upper-right corner disappears when the bucket is ready to use.

The travel app, as a REST API backend, will run in the terminal window, which you need to keep open.
Please refer to SDK-specific instructions on how to run the application.

The following figure illustrates the relationship between the different kinds of documents.
It shows the primary key, ID, and type fields that each document has, plus a few representative fields in each type of document.

Figure 1. Documents in the travel app data model

Airline documents

Airline documents contain details about airlines such as the name of the airline, International Air Transport Association (IATA) two-character airline designator, International Civil Aviation Organization (ICAO) three-character airline designator, and the airline call sign.

Route documents

Route documents contain details about flights such as the name of the airline, departure airport, destination airport, number of stops during the flight, type of aircraft, flight number, and flight schedule.

Route documents also contain a foreign key identifier, airlineid, that is used to retrieve the document that contains information about the airline that flies the route.
The value of the airlineid field is identical to the key for the corresponding airline document.

Landmark documents

Landmark documents contain details about points of interest such as hotels.
They include information such as name, location, price, contact information, and the kind of activity that the point of interest provides.

Architecture

The application serves an HTML file named index.html (eg.
from the public path in the Node.js application).
This file contains references to various included script files for front-side JavaScript components such as Bootstrap, jQuery, and AngularJS.
The Angular controller script named script.js, which you can find in the /public/js/ directory, controls how the application interacts with the REST API in the server application.

Figure 2. The Application Services

REST API

The application uses these methods to populate data in the application:

$scope.findFlights, which is a REST API call to the /api/flightPath/findAll endpoint

$scope.findAirports, which is a REST API call to the /api/airport/findAll endpoint

Figure 3. Front End Framework REST calls

Figure 4. REST API for finding airports

The application attempts to find an airport based on the codes used for the name (case sensitive), and codes for Federal Aviation Administration (FAA) or International Civil Aviation Organization (ICAO).
The travel app uses the data model and binds the input field for the from airport to an Angular typeahead directive, which is defined in the index.html file as follows:

The /api/airport/findAll route function in the route.js file points to the corresponding findAll function in the airport module in the /model/airport.js file.
This method allows the user to search by FAA code, ICAO code or airport name.
It then prepares a N1QL query based on the selection criteria and bucket information from the /config.json file.
The query is passed to the Couchbase query service in the /model/db.js module that calls Couchbase.

Using the data model, if you enter SEA, KSEA, or Seattle, the typeahead directive gives you the option to select Seattle Tacoma Intl. To see the results of the query, watch the terminal window in which the Node application is running.
The example is showing an output for the N1QL statements:

You can enable or disable console logging for N1QL statements by changing the value of the showQuery property in the /config.json file to true or false.

Figure 5. REST API for finding flight paths

After the airports are selected and a leave date is entered, the application tries to find route and schedule information for an airline that services the requested flight path.
The call to the REST API /api/flightPath/findAll on the server is initiated when the user clicks the Find Flights button.
The button is defined within the travelForm form element in the index.html file, as shown in the following code snippets:

The travelForm form element contains various Angular validation options that are used with the input directives.
For more information about validation and the input directive see https://docs.angularjs.org/api/ng/directive/input.
After validating the input options, the Angular function in the script.js file is called to find flights.

The findFlights() function checks the form input to determine whether the return option is enabled or disabled.
It then calls the server REST API /api/flightPath/findAll function either once for a one way flight or twice for a round-trip flight.
When it requests the return flight for a round trip, it uses the reverse to and from sequence.

The /api/flightPath/findAll route function in the route.js file points to the corresponding findAll function in the flightPath module, found in the /model/flghtPath.js file.
The findAll function performs several important steps for processing the request to find flights:

It determines the FAA identifier for the to and from airports.

It searches for routes and schedule information based on the source and destination airports and the requested dates.
The collection of schedule documents is nested in the route document for each route.
They are grouped by day of the week (1-7), and the requested dates are compared to the day of the week to see what flights are available on those particular dates.
It returns a list of flights that includes data for the following fields: airline, flight, departure, from, to, and aircraft.

N1QL query anatomy

The Couchbase Query API is a powerful tool for efficient retrieval of information from a document data store.
In each SDK-specific travel application, queries about flights are created by a dedicated module (for example in Node.js, the flightPath.js module).
Here’s an example of a query that finds flights between Seattle-Tacoma International Airport (SEA) and Orlando International Airport (MCO), followed by a description of what’s happening in the query:

N1QL provides JOIN functionality, something previously not possible in a document database.
For two documents to be joined in the result of a SELECT statement, one of them must contain a field whose value is equal to the Couchbase key of the other document.
The following example shows two documents that demonstrate that requirement and a SELECT statement that joins them:

The data model for the travel application includes an airlineid field in each route document.
That airlineid field is used as a foreign key identifier and corresponds to the key for an airline document.
To select the airline name a.name, the query uses the following clause: JOIN `travel-sample` a ON KEYS r.airlineid.

One of the most powerful features available in the Couchbase Query API is the ability to UNNEST or flatten,the results returned in the SELECT statement.
In the data model for the travel application, each route document contains a nested collection of schedule documents.
To alleviate a complicated JSON parsing code pattern for the return results, you can UNNEST the schedule documents, so they become the root-level fields in the returned results.

Standard SQL syntax is used in the WHERE clause for the SELECT statement.
The result set is ordered by the a.name field, which contains the airline name.

Using the Travel App

Open a browser and navigate to the login URL that was displayed when you started the app.

Sign in to Couchbase Travel by providing your credentials:

Find a flight:

In the Airport or City section, enter an airport code or city name in the From and To fields.

In the Travel Dates section, select Leave and Return dates by using the date picker that pops up when you click the date fields.

Click Find Flights.

The app displays the available flights for the outbound and return legs of the trip.