diff --git a/scripts/analytics/mongodb/queries/averageLevelPlaytimes.js b/scripts/analytics/mongodb/queries/averageLevelPlaytimes.js index d3a889202..3119e2292 100644 --- a/scripts/analytics/mongodb/queries/averageLevelPlaytimes.js +++ b/scripts/analytics/mongodb/queries/averageLevelPlaytimes.js @@ -1,65 +1,41 @@ -// Average level playtimes by campaign +// Average level playtimes in seconds by campaign, broken up by course and campaign levels // Usage: // mongo <address>:<port>/<database> <script file> -u <username> -p <password> // NOTE: faster to use find() instead of aggregate() -// NOTE: faster to ask for one level at a time. also keeps levels in campaign order +// NOTE: faster to ask for one level at a time. -// Excluded for one reason or another -// Some relevant code: https://github.com/codecombat/codecombat/blob/master/app/views/play/CampaignView.coffee#L281-L292 -var excludedLevels = ['deadly-dungeon-rescue', 'kithgard-brawl', 'cavern-survival', 'kithgard-mastery', 'destroying-angel', 'kithgard-apprentice', 'wild-horses', 'lost-viking', 'forest-flower-grove', 'boulder-woods', 'the-trials']; +var courseCampaigns = ['intro', 'course-2', 'course-3', 'course-4']; +var individualCampaigns = ['dungeon', 'forest', 'desert', 'mountain']; var scriptStartTime = new Date(); -var startDay = '2015-07-01'; -var endDay = '2015-08-06'; +var startDay = '2015-12-06'; +var endDay = '2015-12-13'; -log("Dates: " + startDay + " to " + endDay); +print("Dates: " + startDay + " to " + endDay); // Print out playtimes for each campaign -var campaigns = getCampaigns(); +var campaigns = getCampaigns(courseCampaigns); + for (var i = 0; i < campaigns.length; i++) { var campaign = campaigns[i]; - // if (campaign.slug !== 'dungeon') continue; - print(campaign.slug + " (free)"); - var total = 0; - - for (var j = 0; j < campaign.free.length; j++) { - var levelSlug = campaign.free[j]; - if (excludedLevels.indexOf(levelSlug) >= 0) continue; - var data = getPlaytimes([levelSlug]); - print(data[levelSlug].average + "\t" + data[levelSlug].count + "\t" + levelSlug); - total += data[levelSlug]; - } - // print(parseInt(total/60/60) + "\t\t total hours"); - total = 0; - - print(campaign.slug + " (paid)"); - for (var j = 0; j < campaign.paid.length; j++) { - var levelSlug = campaign.paid[j]; - if (excludedLevels.indexOf(levelSlug) >= 0) continue; - var data = getPlaytimes([levelSlug]); - if (data[levelSlug]) { - print(data[levelSlug].average + "\t" + data[levelSlug].count + "\t" + levelSlug); - total += data[levelSlug]; + print(campaign.slug); + print("Sessions\tAverage\tSessions\tAverage\tLevel"); + for (var j = 0; j < campaign.levelSlugs.length; j++) { + var levelSlug = campaign.levelSlugs[j]; + var levelPlaytimes = getPlaytimes([levelSlug]); + if (levelPlaytimes[levelSlug]) { + print(levelPlaytimes[levelSlug].campaign.count, + '\t', levelPlaytimes[levelSlug].campaign.average, + '\t', levelPlaytimes[levelSlug].course.count, + '\t', levelPlaytimes[levelSlug].course.average, + '\t', levelSlug); } else { - print("0\t0\t" + levelSlug); + print(0, '\t', 0, '\t', 0, '\t', 0, '\t', levelSlug); } } - // print(parseInt(total/60/60) + "\t\t total hours"); - total = 0; - - print(campaign.slug + " (replayable)"); - for (var j = 0; j < campaign.replayable.length; j++) { - var levelSlug = campaign.replayable[j]; - if (excludedLevels.indexOf(levelSlug) >= 0) continue; - var data = getPlaytimes([levelSlug]); - print(data[levelSlug].average + "\t" + data[levelSlug].count + "\t" + levelSlug); - total += data[levelSlug]; - } - // print(parseInt(total/60/60) + "\t\t total hours"); - // break; } @@ -79,32 +55,32 @@ function objectIdWithTimestamp(timestamp) { return constructedObjectId } -function getCampaigns() { +function getCampaigns(campaignSlugs) { var campaigns = []; - var cursor = db.campaigns.find({}, {slug: 1, levels: 1}); + var cursor = db.campaigns.find({slug: {$in: campaignSlugs}}, {slug: 1, levels: 1}); var allFree = 0; var allpaid = 0; while (cursor.hasNext()) { var doc = cursor.next(); if (doc.slug === 'auditions') continue; - var campaign = {slug: doc.slug, free: [], paid: [], replayable: []}; + var campaign = {slug: doc.slug, levelSlugs: []}; for (var levelID in doc.levels) { - if (doc.levels[levelID].replayable) { - campaign.replayable.push(doc.levels[levelID].slug); - } - else if (doc.levels[levelID].requiresSubscription) { - campaign.paid.push(doc.levels[levelID].slug); - } - else { - campaign.free.push(doc.levels[levelID].slug); - } + campaign.levelSlugs.push(doc.levels[levelID].slug); } campaigns.push(campaign); } + + campaigns.sort(function (a, b) { + if (campaignSlugs.indexOf(a.slug) < campaignSlugs.indexOf(b.slug)){ + return -1; + } + return 1; + }); return campaigns; } function getPlaytimes(levelSlugs) { + // printjson(levelSlugs); var startObj = objectIdWithTimestamp(ISODate(startDay + "T00:00:00.000Z")); var endObj = objectIdWithTimestamp(ISODate(endDay + "T00:00:00.000Z")) var cursor = db['level.sessions'].find({ @@ -116,21 +92,49 @@ function getPlaytimes(levelSlugs) { {_id: {$gte: startObj}}, {_id: {$lt: endObj}} ] - }); + }, {heroConfig: 1, levelID: 1, playtime: 1}); var playtimes = {}; while (cursor.hasNext()) { var myDoc = cursor.next(); var levelID = myDoc.levelID; - if (!playtimes[levelID]) playtimes[levelID] = []; - playtimes[levelID].push(myDoc.playtime); + + if (!playtimes[levelID]) playtimes[levelID] = {campaign: [], course: []}; + if (myDoc.heroConfig) { + playtimes[levelID].campaign.push(myDoc.playtime); + } + else { + playtimes[levelID].course.push(myDoc.playtime); + } } + // printjson(playtimes); var data = {}; for (levelID in playtimes) { - var total = playtimes[levelID].reduce(function(a, b) {return a + b;}); - data[levelID] = {count: playtimes[levelID].length, total: total}; - data[levelID]['average'] = parseInt(total / playtimes[levelID].length); + var campaignTotal = 0; + var courseTotal = 0; + if (playtimes[levelID].campaign.length > 0) { + campaignTotal = playtimes[levelID].campaign.reduce(function(a, b) {return a + b;}); + } + if (playtimes[levelID].course.length > 0) { + courseTotal = playtimes[levelID].course.reduce(function(a, b) {return a + b;}); + } + + var campaignAverage = parseInt(playtimes[levelID].campaign.length > 0 ? parseInt(campaignTotal / playtimes[levelID].campaign.length): 0); + var courseAverage = parseInt(playtimes[levelID].course.length > 0 ? parseInt(courseTotal / playtimes[levelID].course.length): 0); + + data[levelID] = { + campaign: { + count: playtimes[levelID].campaign.length, + total: campaignTotal, + average: campaignAverage + }, + course: { + count: playtimes[levelID].course.length, + total: courseTotal, + average: courseAverage + } + }; } return data; } diff --git a/scripts/analytics/mongodb/queries/campaignCompletionCounts.js b/scripts/analytics/mongodb/queries/campaignCompletionCounts.js new file mode 100644 index 000000000..36ade5840 --- /dev/null +++ b/scripts/analytics/mongodb/queries/campaignCompletionCounts.js @@ -0,0 +1,106 @@ +// Campaign completion counts + +// Usage: +// mongo <address>:<port>/<database> <script file> -u <username> -p <password> + +var courseCampaigns = ['intro', 'course-2', 'course-3', 'course-4']; +var individualCampaigns = ['dungeon', 'forest', 'desert', 'mountain']; + +var scriptStartTime = new Date(); +var startDay = '2015-11-08'; +var endDay = '2015-11-15'; // Not inclusive + +log("Dates: " + startDay + " to " + endDay); + +var campaigns = getCampaigns(courseCampaigns); +// var campaigns = getCampaigns(individualCampaigns); +// printjson(campaigns); + +for (var i = 0; i < campaigns.length; i++) { + var campaign = campaigns[i]; + print(campaign.slug); + print("Total\tCampaign\tCourse\tLevel"); + var completionCounts = getCompletionCounts(campaign.levelSlugs); + for (var j = 0; j < campaign.levelSlugs.length; j++) { + var levelSlug = campaign.levelSlugs[j]; + if (completionCounts[levelSlug]) { + print(completionCounts[levelSlug].campaign + completionCounts[levelSlug].course, + '\t', completionCounts[levelSlug].campaign, + '\t', completionCounts[levelSlug].course, + '\t', levelSlug); + } + else { + print(0, '\t', 0, '\t', 0, '\t', levelSlug); + } + } +} + +log("Script runtime: " + (new Date() - scriptStartTime)); + +function log(str) { + print(new Date().toISOString() + " " + str); +} + +function objectIdWithTimestamp(timestamp) { + // Convert string date to Date object (otherwise assume timestamp is a date) + if (typeof(timestamp) == 'string') timestamp = new Date(timestamp); + // Convert date object to hex seconds since Unix epoch + var hexSeconds = Math.floor(timestamp/1000).toString(16); + // Create an ObjectId with that hex timestamp + var constructedObjectId = ObjectId(hexSeconds + "0000000000000000"); + return constructedObjectId +} + +function getCampaigns(campaignSlugs) { + var campaigns = []; + var cursor = db.campaigns.find({slug: {$in: campaignSlugs}}, {slug: 1, levels: 1}); + var allFree = 0; + var allpaid = 0; + while (cursor.hasNext()) { + var doc = cursor.next(); + if (doc.slug === 'auditions') continue; + var campaign = {slug: doc.slug, levelSlugs: []}; + for (var levelID in doc.levels) { + campaign.levelSlugs.push(doc.levels[levelID].slug); + } + campaigns.push(campaign); + } + + campaigns.sort(function (a, b) { + if (campaignSlugs.indexOf(a.slug) < campaignSlugs.indexOf(b.slug)){ + return -1; + } + return 1; + }); + return campaigns; +} + +function getCompletionCounts(levelSlugs) { + var startObj = objectIdWithTimestamp(ISODate(startDay + "T00:00:00.000Z")); + var endObj = objectIdWithTimestamp(ISODate(endDay + "T00:00:00.000Z")) + var cursor = db['level.sessions'].find({ + $and: + [ + {"state.complete": true}, + {levelID: {$in: levelSlugs}}, + {_id: {$gte: startObj}}, + {_id: {$lt: endObj}} + ] + }, {heroConfig: 1, levelID: 1}); + + var completionCounts = {}; + while (cursor.hasNext()) { + var myDoc = cursor.next(); + var levelID = myDoc.levelID; + + if (!completionCounts[levelID]) completionCounts[levelID] = {campaign: 0, course: 0}; + if (myDoc.heroConfig) { + completionCounts[levelID].campaign++; + } + else { + completionCounts[levelID].course++; + } + } + + return completionCounts; +}