Skip to the content.

Databases

My work in this category builds on the previous two categories by enhancing the server component to record temperature data to a time-series database and the browser interface to display a graph of recent temperature readings. While enhancing the artifact, I learned about the time-series functionality in MongoDB. I have previous experience with traditional collections in MongoDB from this computer science program and in my career, but I had not yet explored the new time-series support. Learning how to use the aggregation functionality to exploit the time-series storage format was challenging, but interesting. I also explored the use of the Plotly JavaScript library for presenting graphs in the browser which I had not used previously. It was challenging to find an optimal data format for returning historical temperature data in a format directly suitable for the graphing library.

Browser Interface with History

Building on the MongoDB database I used for the initial server implementation, I created a new collection using the time-series support found in the latest MongoDB release. This feature optimizes the collection for the storage of timed measurements and is well-suited to capturing temperature measurements in real time. The time-series collection works in conjunction with the aggregation facilities in MongoDB to allow for efficient reporting of historical data.

/**
 * queries aggregated temperature history from the time-series collection in MongoDB
 * using average temperatures over 15 minute intervals
 * 
 * @param thermostatId the ID of the thermostat to report on
 * @param from the start fo the time period to report on
 * @param to the end of the time period to report on
 * @return the aggregated results in a format suitable for graphing on the front-end 
 */
public TemperatureHistory getTemperatureHistory(String thermostatId, Instant from, Instant to) {
    var unit = "minute";
    var binSize = 15;
    /*
     * match all documents for the given thermostatId within the time period
     * 
     * { $match: { $and: [ { $eq:  [ "thermostatId", thermostatId ] },
     *                     { $gte: [ "timestamp",    from         ] },
     *                     { $lt:  [ "timestamp",    to           ] } ] } }
     */
    var match = match(and(eq("thermostatId", thermostatId), gte("timestamp", from), lt("timestamp", to)));
    /*
     * exclude the _id field, include termparature and round timestamp up to the next 15 minute boundary
     * 
     * { $project: { _id: 0,
     *               temperature: 1,
     *               timestamp: {
     *                   $dateAdd: {
     *                       startDate: {
     *                           $dateTrunc: {
     *                               date: "$timestamp",
     *                               unit: "minute",
     *                               binSize: 15
     *                           },
     *                       },
     *                       unit: "minute",
     *                       amount: 15
     *                   }
     *               } } }
     */
    var project = project(fields(excludeId(), include("temperature"), computed("timestamp", computed("$dateAdd",
            new BasicDBObject("startDate", computed("$dateTrunc",
                    new BasicDBObject("date", "$timestamp").append("unit", unit).append("binSize", binSize)))
                            .append("unit", unit).append("amount", binSize)))));
    /*
     * average all temperatures from the same 15 minute interval
     * 
     * { $group: { _id: "$timestamp",
     *             temperature: { $avg: "$temperature" } } }
     */
    var group = group("$timestamp", avg("temperature", "$temperature"));
    /*
     * sort by _id (timestamp)
     * 
     * { $sort: { _id: 1 } }
     */
    var sort = sort(include("_id"));
    var documents = mongoCollection().aggregate(List.of(match, project, group, sort), Document.class);
    return TemperatureHistory.of(documents, "_id", "temperature");
}

With the new collection in place, I updated the server to record temperature readings whenever a change is sent from the thermostat and to request an update from the thermostat whenever a minute goes by without a change. Then I updated the web interface to show a graph of the recent temperature changes by dynamically querying the database for the average temperature recorded for 15-minute periods.

The complete source code for the server component including this enhancment is available here.


« Algorithms and Data Structure