Skip to content

MongoDB->Postgres Migration (Part 1 of 2): Migrate team data from Mongoid to ActiveRecord #227

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 29 commits into from
Nov 10, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
0fb8fba
don't rehash the script/ide startup
just3ws Nov 4, 2014
118c24b
:skull: mongodb
seuros Sep 13, 2014
6c6ea3d
WIP: Verifying that the teams are migrated correctly
just3ws Sep 14, 2014
fcccc1f
Continuing to verify
just3ws Sep 14, 2014
f40ff78
Verify Team#account and Team#account.plans migration
just3ws Sep 15, 2014
4e0a2df
More verfications. Needed to mark the source for the follower class
just3ws Sep 15, 2014
adad96c
Retina favicons, #270
DaneLyons Sep 9, 2014
b3beec7
retina favicons
DaneLyons Sep 9, 2014
a16be40
Bumped gem
just3ws Sep 22, 2014
7a89d9a
Script to generate a new box
just3ws Sep 25, 2014
be6128a
Update CONTRIBUTING.md
just3ws Oct 4, 2014
4b8ca84
Use Airbrake.io
just3ws Oct 7, 2014
6607d51
:skull: mongodb
seuros Sep 13, 2014
539981a
WIP: Verifying that the teams are migrated correctly
just3ws Sep 14, 2014
a3d5275
Added tasks copied from ASM to make downloading the production data e…
just3ws Oct 15, 2014
5fc24d5
Updated Vagrant configuration to include cachier and apt dependencies
just3ws Oct 15, 2014
192367d
Tweaked the precision on the calculated scores for conversion from Mo…
just3ws Oct 20, 2014
d08c40c
Touched Gemfile.lock and Rakefile
just3ws Oct 21, 2014
9dd9121
Less noise from logs
just3ws Nov 4, 2014
aa5d18b
Updated the Avatar migration to move over the image name and set the …
just3ws Nov 4, 2014
6f38f04
Set the score related values directly along with the slug
just3ws Nov 5, 2014
b17c946
Cleaned dead code from migrator
just3ws Nov 5, 2014
25e1116
Found that team members that weren't migrated were due STRIPE keys mi…
just3ws Nov 6, 2014
864349e
Removed verifications that aren't quite right 100% but have been prov…
just3ws Nov 7, 2014
5be30dc
Cleaning up to get the new data working
just3ws Nov 10, 2014
2b77984
Make the MongoDB database configurable
just3ws Nov 10, 2014
d312e6b
Updated schema to latest migration
just3ws Nov 10, 2014
946cdca
Merged mongoid changes and the updated db schema
just3ws Nov 10, 2014
dcbccf3
Updated with the latest migration
just3ws Nov 10, 2014
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,5 @@ vcr_cassettes
dump
BACKUP
Guardfile
verification.log
npm-debug.log
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ If you're running Windows, [here's a guide written by one of our members on how
1. **Install VirtualBox**

Grab the VirtualBox installer from **[here](https://www.virtualbox.org/wiki/Download_Old_Builds_4_3)**.

![Download the Vbox installer and extensions from here](https://www.evernote.com/shard/s13/sh/68b6a635-7a80-444b-a210-c1aa61405efc/955c950ebafc46f0f1069e27e85bb120)

The _required_ version is **VirtualBox 4.3.12.**
Expand Down
4 changes: 4 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,9 @@ gem 'sitemap_generator'
gem 'tweet-button'
gem 'local_time'

gem 'elasticsearch-model'
gem 'elasticsearch-rails'

# DROP BEFORE RAILS 4
# Mongo
gem 'mongoid'
Expand Down Expand Up @@ -182,6 +185,7 @@ group :test do
gem 'timecop'
gem 'vcr'
gem 'webmock', '<1.16'
gem 'stripe-ruby-mock', git: 'https://github.com/rebelidealist/stripe-ruby-mock', branch: 'live-tests'
end

gem 'airbrake'
Expand Down
33 changes: 33 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,16 @@ GIT
mime-types (>= 1.25, < 3.0)
rest-client (~> 1.4)

GIT
remote: https://github.com/rebelidealist/stripe-ruby-mock
revision: f694a2792bf817932b3e9c4fe7ec51d00da03b4b
branch: live-tests
specs:
stripe-ruby-mock (2.0.0)
dante (>= 0.2.0)
jimson-temp
stripe (>= 1.15.0)

GEM
remote: https://rubygems.org/
remote: https://rails-assets.org/
Expand Down Expand Up @@ -106,6 +116,7 @@ GEM
rack (>= 0.9.0)
binding_of_caller (0.7.2)
debug_inspector (>= 0.0.1)
blankslate (3.1.3)
bson (1.10.2)
bson_ext (1.10.2)
bson (~> 1.10.2)
Expand Down Expand Up @@ -176,6 +187,7 @@ GEM
httparty (~> 0.10)
json
curb (0.8.6)
dante (0.2.0)
database_cleaner (1.3.0)
debug_inspector (0.0.2)
debugger-linecache (1.2.0)
Expand All @@ -195,6 +207,19 @@ GEM
execjs
eco-source (1.1.0.rc.1)
ejs (1.1.1)
elasticsearch (1.0.4)
elasticsearch-api (= 1.0.4)
elasticsearch-transport (= 1.0.4)
elasticsearch-api (1.0.4)
multi_json
elasticsearch-model (0.1.4)
activesupport (> 3)
elasticsearch (> 0.4)
hashie
elasticsearch-rails (0.1.4)
elasticsearch-transport (1.0.4)
faraday
multi_json
em-http-request (1.1.2)
addressable (>= 2.3.4)
cookiejar
Expand Down Expand Up @@ -330,6 +355,11 @@ GEM
jbuilder (2.1.3)
activesupport (>= 3.0.0, < 5)
multi_json (~> 1.2)
jimson-temp (0.9.5)
blankslate (>= 3.1.2)
multi_json (~> 1.0)
rack (~> 1.4)
rest-client (~> 1.0)
journey (1.0.4)
jquery-rails (2.0.3)
railties (>= 3.1.0, < 5.0)
Expand Down Expand Up @@ -758,6 +788,8 @@ DEPENDENCIES
createsend
database_cleaner
dotenv-rails
elasticsearch-model
elasticsearch-rails
ember-rails!
fabrication-rails
faraday (~> 0.8.1)
Expand Down Expand Up @@ -844,6 +876,7 @@ DEPENDENCIES
spring-commands-rspec
squeel (= 1.0.1)
stripe!
stripe-ruby-mock!
strong_parameters
syntax
timecop
Expand Down
280 changes: 280 additions & 0 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,283 @@ require 'rake'
Coderwall::Application.load_tasks

task default: :spec

namespace :team do
task migrate: :environment do
puts '--- Beginning team migration ---'
success = true
begin
Team.each do |team|
begin
puts ">>> Migrating #{team.id}"
TeamMigratorJob.new.perform(team.id.to_s)
rescue => ex
success = false
puts "[#{team.id.to_s}] #{ex} >>\n#{ex.backtrace.join("\n ")}"
end
end
ensure
puts "--- #{success ? 'Successful' : 'Unsuccessful'} team migration ---"
end
end

#
# IMPORTANT: pending_join_requests is a STRING array in Postgres but an INTEGER array in MongoDB.
# IMPORTANT: pending_join_requests is an array of User#id values
#

task verify: :environment do
#ActiveRecord::Base.logger = nil
#Mongoid.logger = nil
#Moped.logger = nil

PgTeam.find_each(batch_size: 100) do |pg_team|
begin
mongo_id = pg_team.mongo_id
mongo_team = Team.find(mongo_id)

# Ignoring:
# - updated_at

puts 'TEAM'

neq(:slug, pg_team, mongo_team, false)

neq_string(:pending_join_requests, pg_team, pg_team.pending_join_requests.map(&:to_i).sort.join(', '), mongo_team, mongo_team.pending_join_requests.map(&:to_i).sort.join(', '), false)

%i(score size total mean median).each do |attr|
neq_dec(attr, pg_team, mongo_team, false)
end

%i(about achievement_count analytics benefit_description_1 benefit_description_2 benefit_description_3 benefit_name_1 benefit_name_2 benefit_name_3 big_image big_quote blog_feed branding country_id created_at endorsement_count facebook featured_banner_image featured_links_title github github_organization_name headline hide_from_featured highlight_tags hiring_tagline interview_steps invited_emails link_to_careers_page location monthly_subscription name number_of_jobs_to_show office_photos organization_way organization_way_name organization_way_photo our_challenge paid_job_posts premium preview_code reason_description_1 reason_description_2 reason_description_3 reason_name_1 reason_name_2 reason_name_3 size stack_list twitter upcoming_events upgraded_at valid_jobs website why_work_image your_impact youtube_url).each do |attr|
neq(attr, pg_team, mongo_team)
end

# TODO: Account
if mongo_team.account.present? && pg_team.account.blank?
puts "account | pg:#{pg_team.id} | mongo:#{mongo_team.id}| The account was not migrated."
end

if mongo_team.account.present? && pg_team.account.present?
check_plans = %i(stripe_card_token stripe_customer_token admin_id).map do |attr|
neq(attr, pg_team.account, mongo_team.account)
end.any? { |x| !x }

# TODO: Plans
if check_plans
left = pg_team.account.plans.pluck(:id).sort
right = mongo_team.account.plan_ids.sort

if left != right
puts "account.plans | pg:#{pg_team.id} | mongo:#{mongo_team.id}| #{left} != #{right}"
end
end
end

#puts 'LOCATIONS'

#pg_team_locations = pg_team.locations
#mongo_team_locations = mongo_team.team_locations

#if mongo_team_locations.count != pg_team_locations.count
#puts "locations | pg:#{pg_team.id} | mongo:#{mongo_team.id}| #{mongo_team_locations.count} != #{pg_team_locations.count}"
#end

## Ignoring:
## - points_of_interest
#pg_team.locations.each do |pg_team_location|
#mongo_team_location = mongo_team.team_locations.select { |tl| tl.name == pg_team_location.name }.first

#%i(address city country description name state_code).each do |attr|
#neq(attr, pg_team_location, mongo_team_location, false)
#end
#end


#puts 'LINKS'

pg_team_links = pg_team.links
mongo_team_links = mongo_team.featured_links

if mongo_team_links.count != pg_team_links.count
puts "links | pg:#{pg_team.id} | mongo:#{mongo_team.id}| #{mongo_team_links.count} != #{pg_team_links.count}"
end

pg_team_links.each do |pg_team_link|
mongo_team_link = mongo_team_links.select { |tl| tl.name == pg_team_link.name }.first

%i(url name).each do |attr|
neq(attr, pg_team_link, mongo_team_link, false)
end
end

#puts 'MEMBERS'

if pg_team.members.count != mongo_team.team_members.count
puts "members | pg:#{pg_team.id} | mongo:#{mongo_team.id}| #{pg_team.members.count} < #{mongo_team.team_members.count}"
end


#puts 'JOBS'

#pg_team.jobs.each do |pg_team_job|
#mongo_team_job = Team.where(id: pg_team_job.team_document_id.to_s).first

#neq(:name, pg_team_job, mongo_team_job, false)
#end

#puts 'FOLLOWERS'

pg_team.followers.each do |pg_team_follower|
mongo_team_follower = Team.where(id: pg_team_follower.mongo_id.to_s).first
# admins
# editors
%i(
about
achievement_count
analytics
benefit_description_1
benefit_description_2
benefit_description_3
benefit_name_1
benefit_name_2
benefit_name_3
big_image
big_quote
blog_feed
branding
country_id
created_at
endorsement_count
facebook
featured_banner_image
featured_links_title
github_organization_name
headline
hide_from_featured
highlight_tags
hiring_tagline
interview_steps
invited_emails
link_to_careers_page
location
monthly_subscription
name
number_of_jobs_to_show
office_photos
organization_way
organization_way_name
organization_way_photo
our_challenge
paid_job_posts
premium
preview_code
reason_description_1
reason_description_2
reason_description_3
reason_name_1
reason_name_2
reason_name_3
slug
stack_list
twitter
upcoming_events
upgraded_at
valid_jobs
website
why_work_image
your_impact
youtube_url
).each do |attr|
neq(attr, pg_team_follower, mongo_team_follower, false)
end
neq_string(:pending_join_requests, pg_team_follower, pg_team_follower.pending_join_requests.map(&:to_i).sort.join(', '), mongo_team_follower, mongo_team_follower.pending_join_requests.map(&:to_i).sort.join(', '), false)

neq_string(:avatar, pg_team_follower, pg_team_follower.avatar.url, mongo_team_follower, mongo_team_follower.avatar.url, false)

%i(score size total mean median).each do |attr|
neq_dec(attr, pg_team_follower, mongo_team_follower, false)
end
end

# TODO: Pending Requests
end
end
end

def neq(attr, pg, mongo, fail_if_neq=true)
left = pg.send(attr)
right = mongo.send(attr)

if left != right
puts "#{attr} | pg:#{pg.id} | mongo:#{mongo.id}| #{left} != #{right}"
true
else
false
end
rescue => ex
print_neq_error(ex)
end

def neq_string(attr, pg, left, mongo, right, fail_if_neq=true)
if left != right
puts "#{attr} | pg:#{pg.id} | mongo:#{mongo.id}| #{left} != #{right}"
true
else
false
end
rescue => ex
print_neq_error(ex)
end

def neq_dec(attr, pg, mongo, fail_if_neq=true)
scale = 7

left = pg.send(attr).to_d.round(scale)
right = mongo.send(attr).to_d.round(scale)


if left != right
puts "#{attr} | pg:#{pg.id} | mongo:#{mongo.id}| #{left} != #{right}"
true
else
false
end
rescue => ex
print_neq_error(ex)
end

def print_neq_error(ex)
puts '*'*80
puts
puts ex
puts
puts '-'*80
puts
ap ex.backtrace
puts
puts '*'*80

require 'pry'; binding.pry
end

task counts: :environment do
pg_team_count = PgTeam.count
puts "PgTeam.count=#{pg_team_count}"
team_count = Team.count
puts "Team.count=#{team_count}"
puts "Unmigrated teams count=#{(team_count - pg_team_count)}"
end


task unmigrated: :environment do
unmigrated_teams = []

Team.all.each do |team|
unmigrated_teams << team.id.to_s unless PgTeam.where(mongo_id: team.id.to_s).exists?
end

puts "Unmigrated teams count=#{unmigrated_teams.count}"
puts "Unmigrated Teams=%w(#{unmigrated_teams.join(' ')})"
end
end
Loading