Blog

Connecting Gaming Devices with wot.io and MongoDB

November 24, 2015 / gaming, chess, android, mongodb, adapters, scriptr / Posted By: wotio team

This post is part 2 of our series on connecting gaming devices with the wot.io data service exchange™.

Routing Gameplay Event Data with wot.io

In the last post we saw that after retrofitting an open source chess application to connect via PubNub, connecting data services was easy since wot.io already has a PubNub adapter. No further changes were required to the application source code to connect to wot.io and send game play events to its data services or connected devices.

In fact, the only thing left to do was decide which wot.io data services to use in conjunction with our gaming system.

Storing Game Statistics with MongoDB

The data format we created for representing game play events uses a JSON variant of Portable Game Notation, or PGN. An example move message might look something like this:

{ 
  "gameId": "123", 
  "game": "continue",
  "user": "wotiosteve", 
  "move": "e2-e4", 
  "moveSeq": 1 
}

and a game ended message might look something like this:

{
  "gameId": "123",
  "black": "wotiosteve",
  "white": "wotiojim",
  "moves": [ [ "f3", "e6" ], [ "g4", "Qh4#" ] ],
  "winner": "wotiosteve",
  "gameResult": "0-1",
  "game": "end",
  "date": "2015.09.21"
}

Since we wanted to store every move made by every player in every game played across our system, we looked at the datastore options available in the wot.io data service exchange. For simplicity, we opted for the No-SQL flexibility of MongoDB and its native support for JSON documents like our game messages.

We chose the PGN format for our moves, but there are other formats that represent chess moves as well. Since MongoDB doesn't require you to define a fixed schema, we could easily add new formats in the future without requiring changes. Whether storing chess moves or IoT data from many different devices or device management platforms, this flexibility makes MongoDB a nice choice for storing data whose format can change over time.

Quick Review on Adapters

As a review, wot.io adapters can be configured to listen for messages on one bus resource and send any messages it may generate to some other bus resource. Typically, these resource paths are set declaratively and stored in the wot.io configuration service, where they are represented as environment variables that get passed into instances of the Docker containers which comprise running data services or adapters.

What that means is that while we can, of course, connect directly to our MongoDB datastore using any of the available drivers or clients, we can also interact with it simply by sending messages on the wot.io bus to and from a MongoDB adapter.

Inserting data into MongoDB

The wot.io adapter for MongoDB makes it possible to insert and query a MongoDB datastore by sending messages on the wot.io bus.

Since each MongoDB adapter can be configured to connect to a specific database and collection in a particular specific instance of the MongoDB data service, to insert a document, one need only route a JSON message that looks like this

[ "insert", {some-JSON-object} ]

to the adapter, et voila, the document will be asynchronously inserted into the configured MongoDB collection.

Reading data from MongoDB

Similarly, we can fetch data by routing a JSON message that looks like this

[ "find", {some-BSON-query} ]

to the same adapter, and the query result will be sent to the destination resource to which the adapter has been bound. (There are additional options for controlling the number of documents in the response, etc., but we'll keep it simple for this example.)

We can also send messages requesting aggregate queries. For example, the message our chess example sends to retrieve statistics for a given user looks like this:

[
  "aggregate",
  [
    {
      "$match": { 
        "gameResult": { "$exists": true },
        "$or": [
          { "white": "wotiosteve" },
          { "black": "wotiosteve" }
        ]
      }
    },
    {
      "$project": {
        "win": {
          "$cond": [ 
            { "$eq": [ "$winner", "wotiosteve" ] }, 
            1, 
            0 
          ]
        },
        "lose": {
          "$cond": [
            { 
              "$and": [
                { "$ne": [ "$winner", null ] },
                { "$ne": [ "$winner", "wotiosteve" ] }
              ]
            },
            1,
            0
          ]
        },
        "draw": {
          "$cond": [
            { "$eq": [ "$winner", null ] },
            1,
            0
          ]
        },
        "user": "$user"
      }
    },
    {
      "$group": {
        "_id": null,
        "total": { "$sum": 1 },
        "win": { "$sum": "$win" },
        "lose": { "$sum": "$lose" },
        "draw": { "$sum": "$draw" }
      }
    },
    {
      "$project": {
        "user": { "$concat": [ "wotiosteve" ] },
        "total": 1,
        "win": 1,
        "lose": 1,
        "draw": 1,
        "action": { "$concat": [ "statistics" ] }
      }
    }
  ]
]

Clearly, MongoDB query documents can get rather complex—but they are also very expressive. And wot.io makes it easy for other data services to interact with our MongoDB datastore.

Composable Data Services

What do we mean by making it easy for other data services to interact with our MongoDB datastore? Well, for example, we might employ a data service like scritpr which allows us to route messages to custom JavaScript logic endpoints.

Let's say that we have coded an algorithm to calculate the minimum number of moves that could have been used to beat an opponent. We can route our game-end messages (like the one shown above) at this data service.

Note that scriptr does not have to possess any MongoDB integration. Nor does the script have to even know that its response might be routed at MongoDB. The "insert" message could just as easily be processed by a different data service—say, Riak. Or both for that matter!

This is what we mean when we say that wot.io's data routing architecture allows for loosely coupled, composable solutions.

Next Time...

Next time we'll take a look at how we can connect another wot.io data service, Pentaho, with our new MongoDB datastore to produce some custom reports.