2014-08-31 21:47:59 +00:00
var authorName = 'Alys' ; // in case script author needs to know when their ...
var authorUuid = 'd904bd62-da08-416b-a816-ba797c9ee265' ; //... own data is done
/ * *
2014-09-01 05:54:44 +00:00
* database _reports / count _users _who _own _specified _gear . js
2014-08-31 21:47:59 +00:00
* https : //github.com/HabitRPG/habitrpg/pull/3884
* /
2014-09-01 05:54:44 +00:00
var thingsOfInterest = {
2014-09-01 09:33:23 +00:00
'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'
]
}
2014-09-01 05:54:44 +00:00
} ;
2014-08-31 21:47:59 +00:00
var mongo = require ( 'mongoskin' ) ;
var _ = require ( 'lodash' ) ;
2014-09-01 05:54:44 +00:00
//////////////// UNCOMMENT ONE OF THESE mongo.db LINES: ////////////////
2014-08-31 21:47:59 +00:00
// 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
2014-09-01 05:54:44 +00:00
// var dbUsers = mongo.db('localhost:27017/habitrpg?auto_reconnect').collection('users'); // for local testing by script author (e.g., vagrant install)
2014-08-31 21:47:59 +00:00
if ( typeof dbUsers == 'undefined' ) { exiting ( 1 , 'Uncomment one of the "var dbUsers" lines!' ) ; }
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)
2014-09-01 05:54:44 +00:00
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?
2014-08-31 21:47:59 +00:00
console . warn ( 'Finding data...' ) ;
var progressCount = 1000 ;
var count = 0 ;
dbUsers . findEach ( query , fields , { batchSize : 250 } , function ( err , user ) {
if ( err ) { return exiting ( 1 , 'ERROR! ' + err ) ; }
if ( ! user ) {
console . warn ( 'All users found.' ) ;
return displayData ( ) ;
}
count ++ ;
2014-09-01 05:54:44 +00:00
_ . each ( thingsOfInterest , function ( obj , label ) {
2014-09-01 09:33:23 +00:00
var data _path = obj [ 'data_path' ] ;
var items = obj [ 'items' ] ;
var identifyOwnershipWith = obj [ 'identifyOwnershipWith' ] ;
var userOwns = path ( user , data _path ) ;
_ . each ( items , function ( item ) {
if ( ( identifyOwnershipWith == 'exists' && item in userOwns ) ||
( identifyOwnershipWith == 'true' && userOwns [ item ] )
) {
if ( ! thingsFound [ label ] ) { thingsFound [ label ] = { } ; }
thingsFound [ label ] [ item ] = ( thingsFound [ label ] [ item ] || 0 ) + 1 ;
// console.warn(user.auth.local.username + ": " + label + ": " + item); // good for testing, bad for privacy
}
} ) ;
} ) ;
2014-08-31 21:47:59 +00:00
if ( count % progressCount == 0 ) console . warn ( count + ' ' + user . _id ) ;
if ( user . _id == authorUuid ) console . warn ( authorName + ' processed' ) ;
2014-09-01 05:54:44 +00:00
if ( user . _id == '9' ) console . warn ( 'lefnire' + ' processed' ) ;
2014-08-17 07:25:53 +00:00
} ) ;
2014-08-31 21:47:59 +00:00
function displayData ( ) {
2014-09-01 09:33:23 +00:00
var today = yyyymmdd ( new Date ( ) ) ;
var csvReport = '' ;
var textReport = today + '\n' ;
_ . each ( thingsFound , function ( obj , label ) {
csvReport += '\n"' + label + '"' + '\n' ;
textReport += '\n' + label + ':\n' ;
var csvHeader = '"date"' ; // heading row in CSV data
var csvData = '"' + today + '"' ; // data row in CSV data
var sortedKeys = _ . sortBy ( _ . keys ( obj ) , function ( key ) { return key ; } ) ;
_ . each ( sortedKeys , function ( key ) {
var value = obj [ key ] ;
csvHeader += ',"' + key + '"' ;
csvData += ',"' + ( value || 0 ) + '"' ;
textReport += '\t' + key + ': ' + value + '\n' ;
} ) ;
csvReport += csvHeader + '\n' + csvData + '\n' ;
} ) ;
console . log ( '\nCSV DATA:\n' + csvReport + '\n\n' +
'READABLE DATA:\n\n' + textReport + '\n\n' ) ;
console . warn ( count + ' users searched (should be >400k)\n' ) ;
// NB: "should be" assumes that no query filter was applied to findEach
2014-08-31 21:47:59 +00:00
return exiting ( 0 ) ;
}
2014-09-01 05:54:44 +00:00
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 ) ) ;
* /
2014-09-01 09:33:23 +00:00
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 ;
2014-09-01 05:54:44 +00:00
}
2014-08-31 21:47:59 +00:00
2014-08-17 07:25:53 +00:00
function yyyymmdd ( date ) {
var yyyy = date . getFullYear ( ) . toString ( ) ;
var mm = ( date . getMonth ( ) + 1 ) . toString ( ) ;
var dd = date . getDate ( ) . toString ( ) ;
return yyyy + "-" + ( mm [ 1 ] ? mm : "0" + mm [ 0 ] ) + "-" + ( dd [ 1 ] ? dd : "0" + dd [ 0 ] ) ;
}
2014-08-31 21:47:59 +00:00
function exiting ( code , msg ) {
code = code || 0 ; // 0 = success
if ( code && ! msg ) { msg = 'ERROR!' ; }
if ( msg ) {
if ( code ) { console . error ( msg ) ; }
else { console . log ( msg ) ; }
}
process . exit ( code ) ;
}
2014-08-17 07:25:53 +00:00
2014-09-01 05:54:44 +00:00
/ * S A M P L E O U T P U T ( S T D O U T a n d S T D E R R ) :
$ node database _reports / count _users _who _own _specified _gear . js
Finding data ...
Alys processed
lefnire processed
All users found .
2014-08-17 07:25:53 +00:00
CSV DATA :
2014-09-01 05:54:44 +00:00
"Unconventional Armor ownership"
2014-09-01 09:33:23 +00:00
"date" , "back_special_wondercon_black" , "back_special_wondercon_red" , "body_special_wondercon_black" , "body_special_wondercon_gold" , "body_special_wondercon_red" , "headAccessory_special_wondercon_black" , "headAccessory_special_wondercon_red"
"2014-09-01" , "7" , "7" , "7" , "7" , "7" , "7" , "9"
2014-09-01 05:54:44 +00:00
"Spooky Skins purchases"
2014-09-01 09:33:23 +00:00
"date" , "ghost" , "monster" , "pumpkin" , "shadow" , "skeleton" , "zombie"
"2014-09-01" , "2" , "3" , "3" , "6" , "4" , "3"
2014-09-01 05:54:44 +00:00
2014-08-17 07:25:53 +00:00
READABLE DATA :
2014-09-01 05:54:44 +00:00
2014 - 09 - 01
2014-09-01 09:33:23 +00:00
Unconventional Armor ownership :
back _special _wondercon _black : 7
back _special _wondercon _red : 7
body _special _wondercon _black : 7
body _special _wondercon _gold : 7
body _special _wondercon _red : 7
headAccessory _special _wondercon _black : 7
headAccessory _special _wondercon _red : 9
Spooky Skins purchases :
ghost : 2
monster : 3
pumpkin : 3
shadow : 6
skeleton : 4
zombie : 3
2014-08-17 07:25:53 +00:00
2014-09-01 05:54:44 +00:00
400100 users searched ( should be > 400 k )
2014-08-31 21:47:59 +00:00
2014-09-01 05:54:44 +00:00
* /