From 5b333a29ab18111fd206fde649a5ed2de242da8d Mon Sep 17 00:00:00 2001 From: Alice Harris Date: Mon, 1 Sep 2014 15:54:44 +1000 Subject: [PATCH] add Spooky Skins; improve report to use node.js stream-based code --- .../count_users_who_own_specified_gear.js | 212 ++++++++++-------- 1 file changed, 121 insertions(+), 91 deletions(-) diff --git a/database_reports/count_users_who_own_specified_gear.js b/database_reports/count_users_who_own_specified_gear.js index 2e66b12bb3..ecacaf16c9 100644 --- a/database_reports/count_users_who_own_specified_gear.js +++ b/database_reports/count_users_who_own_specified_gear.js @@ -1,63 +1,59 @@ -var migrationName = '20140829_change_headAccessory_to_eyewear'; var authorName = 'Alys'; // in case script author needs to know when their ... var authorUuid = 'd904bd62-da08-416b-a816-ba797c9ee265'; //... own data is done /** - * count_users_who_own_specified_gear.js + * database_reports/count_users_who_own_specified_gear.js * https://github.com/HabitRPG/habitrpg/pull/3884 */ +var thingsOfInterest = { + 'Unconventional Armor ownership': { + 'data_path': 'items.gear.owned', + 'identifyOwnershipWith': 'exists', + 'items': [ + 'headAccessory_special_wondercon_red', + 'headAccessory_special_wondercon_black', + 'back_special_wondercon_black', + 'back_special_wondercon_red', + 'body_special_wondercon_red', + 'body_special_wondercon_black', + 'body_special_wondercon_gold' + ], + }, + 'Spooky Skins purchases': { + 'data_path': 'purchased.skin', + 'identifyOwnershipWith': 'true', + 'items': [ + 'monster', + 'pumpkin', + 'skeleton', + 'zombie', + 'ghost', + 'shadow' + ] + } +}; + var mongo = require('mongoskin'); var _ = require('lodash'); -/////////////////// UNCOMMENT *ONE* OF THESE LINES: /////////////////// +//////////////// UNCOMMENT ONE OF THESE mongo.db LINES: //////////////// // var dbUsers = mongo.db('lefnire:mAdn3s5s@charlotte.mongohq.com:10015/habitrpg_large?auto_reconnect').collection('users'); // @lefnire production? // var dbUsers = mongo.db('localhost:27017/habitrpg_old?auto_reconnect').collection('users'); // @lefnire habitrpg_old -var dbUsers = mongo.db('localhost:27017/habitrpg?auto_reconnect').collection('users'); // for local testing by script author (e.g., vagrant install) +// var dbUsers = mongo.db('localhost:27017/habitrpg?auto_reconnect').collection('users'); // for local testing by script author (e.g., vagrant install) if (typeof dbUsers == 'undefined') { exiting(1, 'Uncomment one of the "var dbUsers" lines!'); } -var thingsOfInterest = { - 'items.gear.owned': [ - 'headAccessory_special_wondercon_red', - 'headAccessory_special_wondercon_black', - 'back_special_wondercon_black', - 'back_special_wondercon_red', - 'body_special_wondercon_red', - 'body_special_wondercon_black', - 'body_special_wondercon_gold' - ], - 'purchased.skin': [ - 'monster', - 'pumpkin', - 'skeleton', - 'zombie', - 'ghost', - 'shadow' - ] -}; - -var thingsOfInterest = [ // TST - 'headAccessory_special_wondercon_red', - 'headAccessory_special_wondercon_black', - 'back_special_wondercon_black', - 'back_special_wondercon_red', - 'body_special_wondercon_red', - 'body_special_wondercon_black', - 'body_special_wondercon_gold' -]; - -var query = {}; // Not worth limiting search data with query and fields since -var fields = {}; // this will be run over a local copy of the database? - var thingsFound = {}; // each key is one "thing" from thingsOfInterest, // and the value for that key is the number of users who own it // (for items, 'owned' values of both true and false are counted // to include items lost on death) +var query = {}; // Not worth limiting search data with query and fields since +var fields = {}; // this will be run over a local copy of the database? + console.warn('Finding data...'); var progressCount = 1000; var count = 0; -// db.users.find().forEach(function(user) { ... }); dbUsers.findEach(query, fields, {batchSize:250}, function(err, user) { if (err) { return exiting(1, 'ERROR! ' + err); } if (!user) { @@ -66,61 +62,75 @@ dbUsers.findEach(query, fields, {batchSize:250}, function(err, user) { } count++; + _.each(thingsOfInterest,function(obj,label){ + var data_path = obj['data_path']; + var items = obj['items']; + var identifyOwnershipWith = obj['identifyOwnershipWith']; + var userOwns = path(user, data_path); -/* - _.each(['costume','equipped'],function(type){ - unset['items.gear.'+type+'.headAccessory'] = ""; - set['items.gear.'+type+'.eyewear'] = newName; - }); - _.each(oldToNew,function(newName,oldName){ - unset['items.gear.owned.'+oldName] = ""; - }); -*/ - - var owned = user.items.gear.owned; - for (var i=0, ic=thingsOfInterest.length; i400k)\n'); + // NB: "should be" assumes that no query filter was applied to findEach - console.log("\nCSV DATA:\n"); - console.log(header); - console.log(data); - console.log("\nREADABLE DATA:\n"); - console.log(today); - console.log(JSON.stringify(thingsFound, null, " ")); - console.log("\n"); - - console.warn('\n' + count + ' users searched\n'); return exiting(0); } +function path(obj, path, def) { +/** + * Retrieve nested item from object/array + * @param {Object|Array} obj + * @param {String} path dot separated + * @param {*} def default value ( if result undefined ) + * @returns {*} + * http://stackoverflow.com/a/16190716 + * Usage: console.log(path(someObject, pathname)); + */ + for(var i = 0,path = path.split('.'),len = path.length; i < len; i++){ + if(!obj || typeof obj !== 'object') return def; + obj = obj[path[i]]; + } + if(obj === 'undefined') return def; + return obj; +} + function yyyymmdd(date) { var yyyy = date.getFullYear().toString(); @@ -141,29 +151,49 @@ function exiting(code, msg) { } -/* SAMPLE OUTPUT: -> load("count_users_who_own_specified_gear.js") +/* SAMPLE OUTPUT (STDOUT and STDERR): +$ node database_reports/count_users_who_own_specified_gear.js + +Finding data... +Alys processed +lefnire processed +All users found. CSV DATA: +"Unconventional Armor ownership" "date","headAccessory_special_wondercon_red","headAccessory_special_wondercon_black","back_special_wondercon_black","back_special_wondercon_red","body_special_wondercon_red","body_special_wondercon_black","body_special_wondercon_gold" -"2014-08-17","5","4","3","3","3","3","3" +"2014-09-01","9","7","7","7","7","7","7" + +"Spooky Skins purchases" +"date","monster","pumpkin","skeleton","zombie","ghost","shadow" +"2014-09-01","3","3","4","3","2","6" + READABLE DATA: -2014-08-17 +2014-09-01 { - "headAccessory_special_wondercon_red": 5, - "headAccessory_special_wondercon_black": 4, - "back_special_wondercon_black": 3, - "back_special_wondercon_red": 3, - "body_special_wondercon_red": 3, - "body_special_wondercon_black": 3, - "body_special_wondercon_gold": 3 + "Unconventional Armor ownership": { + "headAccessory_special_wondercon_red": 9, + "headAccessory_special_wondercon_black": 7, + "back_special_wondercon_black": 7, + "back_special_wondercon_red": 7, + "body_special_wondercon_red": 7, + "body_special_wondercon_black": 7, + "body_special_wondercon_gold": 7 + }, + "Spooky Skins purchases": { + "monster": 3, + "pumpkin": 3, + "skeleton": 4, + "zombie": 3, + "ghost": 2, + "shadow": 6 + } } -true -> -*/ +400100 users searched (should be >400k) +*/