2016-05-01 14:27:04 +00:00
// Migrate challenges collection to new schema (except for members)
2016-04-30 16:34:16 +00:00
// The console-stamp module must be installed (not included in package.json)
// It requires two environment variables: MONGODB_OLD and MONGODB_NEW
// Due to some big user profiles it needs more RAM than is allowed by default by v8 (arounf 1.7GB).
// Run the script with --max-old-space-size=4096 to allow up to 4GB of RAM
2016-05-01 12:46:22 +00:00
console . log ( 'Starting migrations/api_v3/challenges.js.' ) ;
2016-04-30 16:34:16 +00:00
require ( 'babel-register' ) ;
var Q = require ( 'q' ) ;
var MongoDB = require ( 'mongodb' ) ;
var nconf = require ( 'nconf' ) ;
var mongoose = require ( 'mongoose' ) ;
var _ = require ( 'lodash' ) ;
var uuid = require ( 'uuid' ) ;
var consoleStamp = require ( 'console-stamp' ) ;
2016-05-03 21:27:24 +00:00
var fs = require ( 'fs' ) ;
2016-04-30 16:34:16 +00:00
// Add timestamps to console messages
consoleStamp ( console ) ;
// Initialize configuration
require ( '../../website/src/libs/api-v3/setupNconf' ) ( ) ;
var MONGODB _OLD = nconf . get ( 'MONGODB_OLD' ) ;
var MONGODB _NEW = nconf . get ( 'MONGODB_NEW' ) ;
var MongoClient = MongoDB . MongoClient ;
mongoose . Promise = Q . Promise ; // otherwise mongoose models won't work
// Load new models
var NewChallenge = require ( '../../website/src/models/challenge' ) . model ;
var Tasks = require ( '../../website/src/models/task' ) ;
// To be defined later when MongoClient connects
var mongoDbOldInstance ;
var oldChallengeCollection ;
var mongoDbNewInstance ;
var newChallengeCollection ;
var newTaskCollection ;
var BATCH _SIZE = 1000 ;
var processedChallenges = 0 ;
var totoalProcessedTasks = 0 ;
2016-05-03 21:27:24 +00:00
var newTasksIds = { } ; // a map of old id -> [new id, challengeId]
2016-04-30 16:34:16 +00:00
// Only process challenges that fall in a interval ie -> up to 0000-4000-0000-0000
var AFTER _CHALLENGE _ID = nconf . get ( 'AFTER_CHALLENGE_ID' ) ;
var BEFORE _CHALLENGE _ID = nconf . get ( 'BEFORE_CHALLENGE_ID' ) ;
function processChallenges ( afterId ) {
var processedTasks = 0 ;
var lastChallenge = null ;
var oldChallenges ;
var query = { } ;
if ( BEFORE _CHALLENGE _ID ) {
query . _id = { $lte : BEFORE _CHALLENGE _ID } ;
}
if ( ( afterId || AFTER _CHALLENGE _ID ) && ! query . _id ) {
query . _id = { } ;
}
if ( afterId ) {
query . _id . $gt = afterId ;
} else if ( AFTER _CHALLENGE _ID ) {
query . _id . $gt = AFTER _CHALLENGE _ID ;
}
var batchInsertTasks = newTaskCollection . initializeUnorderedBulkOp ( ) ;
var batchInsertChallenges = newChallengeCollection . initializeUnorderedBulkOp ( ) ;
2016-05-01 12:46:22 +00:00
console . log ( ` Executing challenges query. \n Matching challenges after ${ afterId ? afterId : AFTER _CHALLENGE _ID } and before ${ BEFORE _CHALLENGE _ID } (included). ` ) ;
2016-04-30 16:34:16 +00:00
return oldChallengeCollection
. find ( query )
. sort ( { _id : 1 } )
. limit ( BATCH _SIZE )
. toArray ( )
. then ( function ( oldChallengesR ) {
oldChallenges = oldChallengesR ;
console . log ( ` Processing ${ oldChallenges . length } challenges. Already processed ${ processedChallenges } challenges and ${ totoalProcessedTasks } tasks. ` ) ;
if ( oldChallenges . length === BATCH _SIZE ) {
lastChallenge = oldChallenges [ oldChallenges . length - 1 ] . _id ;
}
oldChallenges . forEach ( function ( oldChallenge ) {
var oldTasks = oldChallenge . habits . concat ( oldChallenge . dailys ) . concat ( oldChallenge . rewards ) . concat ( oldChallenge . todos ) ;
delete oldChallenge . habits ;
delete oldChallenge . dailys ;
delete oldChallenge . rewards ;
delete oldChallenge . todos ;
2016-05-01 14:27:04 +00:00
var createdAt = oldChallenge . timestamp ;
2016-05-01 12:46:22 +00:00
oldChallenge . memberCount = oldChallenge . members . length ;
if ( ! oldChallenge . prize <= 0 ) oldChallenge . prize = 0 ;
if ( ! oldChallenge . name ) oldChallenge . name = 'challenge name' ;
if ( ! oldChallenge . shortName ) oldChallenge . name = 'challenge-name' ;
if ( ! oldChallenge . group ) throw new Error ( 'challenge.group is required' ) ;
if ( ! oldChallenge . leader ) throw new Error ( 'challenge.leader is required' ) ;
2016-05-07 15:35:13 +00:00
if ( oldChallenge . leader === '9' ) {
oldChallenge . leader = '00000000-0000-4000-9000-000000000000' ;
}
if ( oldChallenge . group === 'habitrpg' ) {
oldChallenge . group = '00000000-0000-4000-A000-000000000000' ;
}
2016-05-03 21:27:24 +00:00
delete oldChallenge . id ;
2016-04-30 16:34:16 +00:00
var newChallenge = new NewChallenge ( oldChallenge ) ;
2016-05-01 14:27:04 +00:00
newChallenge . createdAt = createdAt ;
2016-04-30 16:34:16 +00:00
oldTasks . forEach ( function ( oldTask ) {
2016-05-03 21:27:24 +00:00
oldTask . _id = uuid . v4 ( ) ;
2016-05-01 21:54:58 +00:00
oldTask . legacyId = oldTask . id ; // store the old task id
2016-04-30 16:34:16 +00:00
delete oldTask . id ;
2016-05-03 21:27:24 +00:00
oldTask . challenge = oldTask . challenge || { } ;
oldTask . challenge . id = newChallenge . _id ;
if ( newTasksIds [ oldTask . legacyId + '-' + newChallenge . _id ] ) {
throw new Error ( 'duplicate :(' ) ;
} else {
newTasksIds [ oldTask . legacyId + '-' + newChallenge . _id ] = oldTask . _id ;
}
2016-05-01 12:46:22 +00:00
oldTask . tags = _ . map ( oldTask . tags || { } , function ( tagPresent , tagId ) {
2016-04-30 16:34:16 +00:00
return tagPresent && tagId ;
} ) ;
2016-05-01 12:46:22 +00:00
if ( ! oldTask . text ) oldTask . text = 'task text' ; // required
2016-05-03 21:27:24 +00:00
oldTask . createdAt = oldTask . dateCreated ;
2016-05-01 12:46:22 +00:00
2016-04-30 16:34:16 +00:00
newChallenge . tasksOrder [ ` ${ oldTask . type } s ` ] . push ( oldTask . _id ) ;
if ( oldTask . completed ) oldTask . completed = false ;
var newTask = new Tasks [ oldTask . type ] ( oldTask ) ;
batchInsertTasks . insert ( newTask . toObject ( ) ) ;
processedTasks ++ ;
} ) ;
batchInsertChallenges . insert ( newChallenge . toObject ( ) ) ;
} ) ;
2016-05-01 14:27:04 +00:00
console . log ( ` Saving ${ oldChallenges . length } challenges and ${ processedTasks } tasks. ` ) ;
2016-04-30 16:34:16 +00:00
2016-05-01 14:27:04 +00:00
return Q . all ( [
batchInsertChallenges . execute ( ) ,
batchInsertTasks . execute ( ) ,
] ) ;
2016-04-30 16:34:16 +00:00
} )
. then ( function ( ) {
totoalProcessedTasks += processedTasks ;
processedChallenges += oldChallenges . length ;
2016-05-01 12:46:22 +00:00
console . log ( ` Saved ${ oldChallenges . length } challenges and their tasks. ` ) ;
2016-04-30 16:34:16 +00:00
2016-05-01 12:46:22 +00:00
if ( lastChallenge ) {
2016-04-30 16:34:16 +00:00
return processChallenges ( lastChallenge ) ;
} else {
2016-05-03 21:27:24 +00:00
console . log ( 'Writing newTasksIds.json...' )
fs . writeFileSync ( 'newTasksIds.json' , JSON . stringify ( newTasksIds , null , 4 ) , 'utf8' ) ;
2016-04-30 16:34:16 +00:00
return console . log ( 'Done!' ) ;
}
} ) ;
}
// Connect to the databases
Q . all ( [
MongoClient . connect ( MONGODB _OLD ) ,
MongoClient . connect ( MONGODB _NEW ) ,
] )
. then ( function ( result ) {
var oldInstance = result [ 0 ] ;
var newInstance = result [ 1 ] ;
mongoDbOldInstance = oldInstance ;
oldChallengeCollection = mongoDbOldInstance . collection ( 'challenges' ) ;
mongoDbNewInstance = newInstance ;
newChallengeCollection = mongoDbNewInstance . collection ( 'challenges' ) ;
newTaskCollection = mongoDbNewInstance . collection ( 'tasks' ) ;
console . log ( ` Connected with MongoClient to ${ MONGODB _OLD } and ${ MONGODB _NEW } . ` ) ;
return processChallenges ( ) ;
} )
. catch ( function ( err ) {
2016-05-01 14:27:04 +00:00
console . error ( err . stack || err ) ;
2016-04-30 16:34:16 +00:00
} ) ;