Skip to content
This repository was archived by the owner on Jan 10, 2020. It is now read-only.

Building your First Neon Application

Eric edited this page Mar 26, 2018 · 3 revisions

This guide will walk you through creating a simple Neon application.

--

What's Needed

Language

Neon provides a JavaScript API, which is the quickest and easiest way to query the Neon server. Alternatively, the Neon server provides web endpoints, so any language capable of executing HTTP GET and POST requests can work with Neon. Using the JavaScript API is the easiest method of working with Neon, so that is the method this guide will cover. This guide assumes you have completed the Quick Start. If you have not, start there.

Starting the Neon server

From your Neon source directory, ensure that Jetty is running.

./gradlew jettyRun

Hello, Neon

To start with, create a minimal Neon web page as below. Create a directory called quickstart under examples. In that directory, create a file called index.html and copy the following into it:

<html>
<head>
    <script src="http://localhost:8080/neon/js/neon.js"></script>
    <script>
        neon.SERVER_URL = "/neon";
        var connection = new neon.query.Connection();
        connection.connect(neon.query.Connection.MONGO, "localhost");

        var query = new neon.query.Query().selectFrom("test", "earthquakes").aggregate("avg", "depth");

        //Execute the query and display the results.
        connection.executeQuery(query, function (result) {
            $("#result").html(JSON.stringify(result.data));
        });
    </script>
</head>
<body>
    <p>Query Results:</p>
    <p id="result"></p>
</body>
</html>https://github.com/NextCenturyCorporation/neon

This page connects to the Neon server at http://localhost:8080/neon (which is where the gradlew jettyRun server appears by default), and executes a query against the example data collection. Navigate to the page http://localhost:8080/neon/examples/quickstart/. The result should look like

Query Results:

[{"_id":{},"avg(depth)":28.116509370540523}]

Handling Updates

The previous example was essentially a static page; it would have been just as easy for a server-side program to run the query and generate the resulting page. Neon is meant for interactive apps, so the next example will allow the user to select the host, database, and collection.

<html>
<head>
    <script src="http://localhost:8080/neon/js/neon.js"></script>
    <script>
        neon.SERVER_URL = "/neon";
        var channel = "dataset_changed";

        // In a separate scope, create the code that will update the 'result' field.
        (function() {
            var messenger = new neon.eventing.Messenger();
            var connection = new neon.query.Connection();
            // This function issues a query and updates the 'result' field.
            var updateResult = function(message) {
                connection.connect(message.datastore, message.hostname);
                var query = new neon.query.Query().selectFrom(message.database, message.table).aggregate("avg", "depth");
                connection.executeQuery(query, function(result) {
                    $("#result").html(JSON.stringify(result.data));
                });
            };
            // Update the result when the dataset changes
            messenger.subscribe(channel, updateResult);
        })();

        neon.ready(function() {
            $("#connectBtn").on('click', function () {
                var message = {
                    datastore: neon.query.Connection.MONGO,
                    hostname: $("#hostName").val(),
                    database: $("#dbName").val(),
                    table: $("#tableName").val()
                };
                var messenger = new neon.eventing.Messenger();
                messenger.publish(channel, message);
            });
        });
    </script>
</head>
<body>
<p>
    Host:<input type="text" id="hostName" value="localhost"/>
    <br/>Database:<input type="text" id="dbName" value="test"/>
    <br/>Table:<input type="text" id="tableName" value="earthquakes"/>
    <br/><button id="connectBtn">Connect</button>
</p>
<p>Query results:</p>
<p id="result"></p>
</body>
</html>

Notice that the click handler and the query code are completely independent thanks to Neon's messenger. When the click handler publishes the message to the 'dataset_changed' channel, any subscriber to that channel will recieve the message. In this case, the function updateResult is called. Any number of publish/subscribes can be used, as long as the matching publish and subscribes use the same channel name.

Also, for a more polished application, you would want to use the Connection functions getDatabaseNames() and getTableNames() to present users with a list of databases and tables on the host that they specified.

Filtering

This section will allow the user to filter by earthquake magnitude.

<html>
<head>
    <script type="text/javascript" src="http://localhost:8080/neon/js/neon.js"></script>
    <script type="text/javascript">
        neon.SERVER_URL = "/neon";
        var channel = "dataset_changed";

        // In a separate scope, create the code that will update the 'result' field.
        (function() {
            var messenger = new neon.eventing.Messenger();
            var connection = new neon.query.Connection();
            var database = "";
            var table = "";
            // This function connects to the database and calls updateResult
            var updateDataset = function(message) {
                connection.connect(message.datastore, message.hostname);

                database = message.database;
                table = message.table;

                updateResult();
            }
            // This function issues a query and updates the 'result' field.
            var updateResult = function() {
                var query = new neon.query.Query()
                    .selectFrom(database, table)
                    .aggregate("avg", "depth");

                connection.executeQuery(query, function(result) {
                    $("#result").html(JSON.stringify(result.data));
                });
            };

            messenger.subscribe(channel, updateDataset);
            messenger.events({
                filtersChanged: updateResult
            });
        })();

        neon.ready(function() {
            var messenger = new neon.eventing.Messenger();
            var connection = new neon.query.Connection();
            var filterKey = "magnitudeFilter";
            var database = "";
            var table = "";

            var updateMagnitudeFilter = function() {
                var magnitude = Number($("#magnitude").val());
                var whereClause = neon.query.where("mag", ">=", magnitude);
                var filter = new neon.query.Filter().selectFrom(database, table).where(whereClause);
                messenger.replaceFilter(filterKey, filter);
            };

            // When the drop down selection changes, update the filters
            $("#magnitude").change(updateMagnitudeFilter);

            $("#connectBtn").on('click', function() {
                var message = {
                    datastore: neon.query.Connection.MONGO,
                    hostname: $("#hostName").val(),
                    database: $("#dbName").val(),
                    table: $("#tableName").val()
                };

                database = message.database;
                table = message.table;

                var messenger = new neon.eventing.Messenger();
                messenger.publish(channel, message);
            });
        });
    </script>
</head>
<body>
<p>
    Host:<input type="text" id="hostName" value="localhost"/>
    <br/>Database:<input type="text" id="dbName" value="test"/>
    <br/>Table:<input type="text" id="tableName" value="earthquakes"/>
    <br/><button id="connectBtn">Connect</button>
</p>
<p>Only earthquakes with magnitude of at least <input type="text" id="magnitude" value="0"/></p>
<p>Query results:</p>
<p id="result"></p>
</body>
</html>

Reload the page, connect to the database, and as you change the magnitude the average will update. A new messenger event has been added that watches the 'filtersChanged' event. When the magnitude changes, it connects to the database and replaces the filter, that has filter key 'magnitudeFilter', with a new one. Additonal filters can be added as long as each ones uses a different filter key. When any filters change, all 'filtersChanged' events are called. Neon has two other events as well: neon.eventing.channels.SELECTION_CHANGED and neon.eventing.channels.CONNECT_TO_HOST.

Clone this wiki locally