Статьи

Создание Великого Mashup: Часть 2

В этом посте подробно описываются функции, используемые Earthquake Explorer , приложением Windows 8, которое отображает информацию о землетрясениях на картах Bing Earthquake Explorer был основан на стартовом наборе коллажей от Earthquakes на github . Прочитайте часть 1 здесь

В первой части мы создали мобильную службу Windows Azure для хранения данных в качестве серверной части нашего гибридного приложения. Большим преимуществом этого подхода является то, что он позволяет нам фильтровать / сортировать / запрашивать данные любым удобным для нас способом, и наше приложение теперь устойчиво к сбоям и изменениям в схеме. В этой части мы собираемся изменить нашу существующую запланированную задачу, чтобы она использовала фактический поток данных USGS и сохранила его в таблице.

Получить данные просто благодаря замечательному каналу GeoJSON, предоставленному USGS. Подробнее об этом читайте здесь:

http://earthquake.usgs.gov/earthquakes/feed/v1.0/

Из нашей запланированной работы мы можем запросить ее следующим образом:

function fetchUSGS() {
    console.log('Starting job');

    var httpRequest = require('request');
    var uri = 'http://earthquake.usgs.gov/earthquakes/feed/v0.1/summary/all_hour.geojson';

    httpRequest(uri, function (err, response, body) {
        if (err) {
            console.warn('Error connecting to service.');
        } else if (response.statusCode !== 200) {
            console.warn('Unexpected reply.');
        } else {
            //got reply, process the results
            var theData = JSON.parse(response.body);
            processData(theData);
        }
    });
}

Мы делаем запрос к каналу (uri) и указываем обратный вызов в качестве встроенной функции. На самом деле не существует надежной обработки ошибок, но в действительности вы ничего не можете сделать в случае ошибки, кроме повторной попытки при следующем запуске задачи. 

Вызов JSON.parse (), естественно, проанализирует текст ответа в хорошую коллекцию объектов, которую мы можем проанализировать. Если мы посмотрим на JSON в Fiddler, вы можете увидеть структуру документа:

образ

JSON содержит коллекцию объектов, где каждый объект содержит объект геометрии, строку идентификатора и объект свойств. Либо с помощью документации на сайте USGS, либо путем изучения результатов, нам нужно знать структуру данных.

Чтобы сделать работу с данными немного проще, мы можем создать простой класс javascript для хранения данных:

function earthquake(item) {
    this.latitude = item.geometry.coordinates[1];
    this.longitude = item.geometry.coordinates[0];
    this.depth = item.geometry.coordinates[2];
    this.usgsId = item.id;
    this.usgsCode = item.properties.code;
    this.tz = item.properties.tz;
    this.mag = item.properties.mag;
    this.time = item.properties.time;
    this.updated = item.properties.updated;
    this.place = item.properties.place;
    this.timestamp = new Date();
}

Здесь есть один сложный момент: идентификатором землетрясения является идентификатор USGS, но все данные в мобильных службах Azure используют bigint в качестве первичного ключа. Когда мы обновляем строку в Mobile Services, мы передаем объект в метод update с соответствующим идентификатором (bigint). (Для удаления требуется только идентификатор bigint.) Да, это небольшая неэффективность, поскольку WAMS использует суррогатный bigint, а USGS предпочитает естественный ключ идентификатора USGS, и для простоты мы будем использовать оба в зависимости от операции. Поскольку мы часто запрашиваем данные, каждый элемент в ленте будет иметь одно из нескольких состояний: он может быть новым (не в базе данных), он может быть уже в базе данных или в базе данных, но Фид содержит обновленные / пересмотренные значения.

function processData(json) {

    var quakesTable = tables.getTable('earthquakes');
    var featureList = json.features;

    featureList.forEach(
        function (item) {
            var eq = new earthquake(item);

            quakesTable.where({
                usgsId: eq.usgsId
            }).read({
                success: function (results) {
                    if (results.length > 0) {
                        //record exists                    
                        eq.id = results[0].id;
                        eq.timestamp = new Date();
                        quakesTable.update(eq);
                      
                    } else {
                        //record doesn't exist                          
                        quakesTable.insert(eq);

                        //send notification?
                        //see next blog post                         
                    }
                }
            });
        }
    );
}

As we iterate through the features, we create an earthquake object from each item.  We then check the table for a record with the same USGS ID property.  If it already exists, we’ll update the row with the information because details may have changed.  Otherwise, we’ll insert it. 

There’s a general inefficiency here that we can deal with if we’re so motivated.  Each item results in a query to see if the item exists, and then a query to either update or insert.  We could simply build a stored procedure that handles either scenario so it’s one call, but because each feed contains about 10 items and this scheduled task is a server-side job, it’s not high on my priority list.  With higher volume apps and/or with client apps, this is a modification you should make.

The other nice thing we can do is send notifications when a new earthquake is found.  For example, if a new earthquake is found in the feed, we can send a live tile notification which would update the tile to look like so:

образ 

For Windows 8 apps, this is really a must-do feature.  Do _something_ (anything!) with the live tile – this will differentiate your app.  Mobile Services can send notifications to Windows Phone, Windows 8, iOS, and Android, so this is a great way to take the app cross platform.  In the next post, we’ll look at how to do a live tile update like the one above.