Fantasy Golf Tracking with Node.js, MongoDB, AngularJS, and Bootstrap - Part 2

I'll address this in parts since the first post really didn't cover anything technical, and was just a bunch of screenshots.

MongoDB Implementation

I previously went over the basic data structure for this app in the previous post.  Teams consist of the team name. Tournaments consist of the key, the name, the start and end date, the course name, the par for the course, and the current round. Also, bools for finished and in progress. Then there is the teams players per tournament which I called teamTournament. It also keeps historical records of their total for that tournament. This lead me to be able to build a leaderboard widget, since the lowest score at the end of the season gets a prize.

Tournament Sample Data

> db.tournaments.find().pretty()
{
        "_id" : ObjectId("53a0964d4fcdf5c39c912acd"),
        "key" : "us-open-2014",
        "name" : "U.S. Open",
        "scoresLocation" : "http://www.pgatour.com/data/r/026/leaderboard-v2.json",
        "startDate" : ISODate("2014-06-12T07:00:00Z"),
        "endDate" : ISODate("2014-06-15T19:00:00Z"),
        "latestRound" : 4,
        "inProgress" : false,
        "isFinished" : true,
        "course" : "Pinehurst No. 2",
        "par" : 70
}

Granted, that inProgress and isFinished can be determined real time, but that's ok.

Team Tournament Sample Data

> db.teamTournament.find().pretty()
{
        "_id" : ObjectId("53a2e61ed42498e823000001"),
        "players" : [
                "28259",
                "28087",
                "21209",
                "08075",
                "31202",
                "28486"
        ],
        "teamId" : ObjectId("53a193fc4fcdf5c39c912af7"),
        "tournamentId" : ObjectId("53a20488d7aee2e01b000001"),
        "tournamentTotal" : 1073
}

I used to use DBRef for referencing other collections, but then I found out that unless you don't know at runtime, you should just use ObjectID.  So my ObjectID of 53a19 etc is in the field of teamId, so I know it's a team reference. If it were called "documentId" and I had collections of "images" and "html snippets" and "swf files", then I could use the DBRef, since it could be one of 3 different collections I want to reference. But since I know, MongoDB says it's much more efficient to just use ObjectID references.

Node.js to Access the Database

As for writing code to access this, I use the Node MongoDB Native library for accessing node, and a helper class that I wrote so I'm not writing lots of code to do things that I do frequently. For instance, my code for getting tournaments looks like this:

this.getTournament = function(db, key, callback){
    dbhelp.findOne(db, "tournaments", { key: key }, function(tournament){
        callback(tournament);
    });
}

this.getCurrentTournament = function(db, callback){
    var upcoming = new Date().addDays(3);
    var past = new Date();

    dbhelp.find(db, "tournaments", { "$or": 
            [ 
                { "startDate": { "$lt": upcoming } },  
                { "endDate": { "$lt": past } }
            ] 
        }, null, { startDate: 1 }, function(tournaments){
        if (tournaments != null && tournaments.length > 0){ return callback(tournaments[0]); }
        else return callback(null);
    });
}

this.getTournaments = function(db, year, callback){
    var start = new Date(year, 0, 1);
    var end = new Date(year, 11, 31);

    dbhelp.find(db, "tournaments", { startDate: { "$gt": start }, endDate: { "$lt": end } }, function(tournaments){
        callback(tournaments);
    });
}

So, you can see, not a lot of code for getting a specific tournament, getting the current tournament, and getting all tournaments this year. (Also I've modified the Date prototype to include a .addDays method).

That is some sample code that I've written for this application. It covers the back end. Next up I'll cover the front end, using AngularJS and Bootstrap to make it work well and look great!

Fantasy Golf Tracking with Node.js, MongoDB, AngularJS, and Bootstrap - Part 1

My family and a bunch of friends are in a fantasy golf league together. The rules are pretty straightforward, although probably not standard.

Rules:
1. Pay $50
2. 10 Tournaments that span the PGA Tour season.
3. Pick 6 golfers before the first tee times on Thursday typically.
4. 4 lowest scores are added and that's your score for each day.
5. If 3 of your players miss the cut, you are assigned the worst score at the end of round 3, pretty much destroying your chance to win.
6. Lowest score wins. $50 payoff for majors (Masters, US Open, British Open, PGA Championship), $25 for the other tournaments.

My brother Pat is the score keeper and chairman of the league. The data collection and reporting was pretty much done in Excel.  This is a fine method for doing such things. The scores would be emailed out along with entertaining commentary.

But then it was my turn to do the data since Pat was going to Boston for the US Open weekend to visit some friends.

Excel was not a viable solution.

I happened to stumble on the PGA Tour Leaderboard website. I noticed that the data is loading in asynchronously, which could only mean AJAX. The question was, which format, and what data is available?

The answer was the start of this application. The data is JSON. And EVERYTHING is available. (I hope I don't get in too much trouble for grabbing it :). Well, everything I needed and some extra stuff.

The first step to building this app was to determine what the Information Architecture was going to look like.  Here's what I came up with:

Teams: Name, Email address of a person in the league.
Tournaments:  Tournament info include URL to the JSON file on pgatour.com, data like start / end date, is it in progress, is it finished.
Team Tournament: Each team's 6 initial golfers for each tournament, and total score recording.

Pulling in the tournament from the pgatour.com JSON file pulls in all of the information required for a tournament in my system, so all that is needed as input is the JSON file URL!

Next you assign teams. There can be 6 max.

Then scores are calculated.

And updated throughout the round, each day, for the whole tournament.

If a player doesn't have 4 players make the cut, they are given a substitute. The worst score from the 3rd round.

That is pretty much everything!  Once again, working with AngularJS is a breeze.

Check out the site at fantasygolf.jasontconnell.com! There you can view the source to get an idea of how it was written. It was very simple that I don't even feel like I can post any difficult code that I wrote, but it's just that it's really cool. Our next tournament is the Congressional next week, I hope everyone in the league uses the site.  I added GA tracking so I'll know for sure :)

Brilliant Business Idea

Dollar Shave Club has this one brilliant business idea as part of their main business model, that is just brilliant and you'd be stupid to not take them up on the offer. I'm talking about the Shave Butter. It's so obvious. Why would anyone get their blades online, shipped automatically every month, but opt to go to the store for shaving cream?  They could offer Dr. Carver's Pungent Shaving Poop Rash Fest Mosquito Urine Cream, and I'd still get it if I didn't have to go to the store.

But really, the Shave Butter is amazing, and I don't want to say that some genius thought of that idea, it's just so obvious that it had to be done, it would just be stupid not to offer it! But that service is great, I've been doing it for almost a year now.