Skip to content

Commit c18713c

Browse files
committed
Merge pull request coderwall#227 from assemblymade/replace_mongodb_with_activerecord
MongoDB->Postgres Migration (Part 1 of 2): Migrate team data from Mongoid to ActiveRecord
2 parents c31b3fb + dcbccf3 commit c18713c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+1134
-269
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,3 +58,5 @@ vcr_cassettes
5858
dump
5959
BACKUP
6060
Guardfile
61+
verification.log
62+
npm-debug.log

CONTRIBUTING.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ If you're running Windows, [here's a guide written by one of our members on how
4949
1. **Install VirtualBox**
5050

5151
Grab the VirtualBox installer from **[here](https://www.virtualbox.org/wiki/Download_Old_Builds_4_3)**.
52-
52+
5353
![Download the Vbox installer and extensions from here](https://www.evernote.com/shard/s13/sh/68b6a635-7a80-444b-a210-c1aa61405efc/955c950ebafc46f0f1069e27e85bb120)
5454

5555
The _required_ version is **VirtualBox 4.3.12.**

Gemfile

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,9 @@ gem 'sitemap_generator'
126126
gem 'tweet-button'
127127
gem 'local_time'
128128

129+
gem 'elasticsearch-model'
130+
gem 'elasticsearch-rails'
131+
129132
# DROP BEFORE RAILS 4
130133
# Mongo
131134
gem 'mongoid'
@@ -182,6 +185,7 @@ group :test do
182185
gem 'timecop'
183186
gem 'vcr'
184187
gem 'webmock', '<1.16'
188+
gem 'stripe-ruby-mock', git: 'https://github.com/rebelidealist/stripe-ruby-mock', branch: 'live-tests'
185189
end
186190

187191
gem 'airbrake'

Gemfile.lock

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,16 @@ GIT
3838
mime-types (>= 1.25, < 3.0)
3939
rest-client (~> 1.4)
4040

41+
GIT
42+
remote: https://github.com/rebelidealist/stripe-ruby-mock
43+
revision: f694a2792bf817932b3e9c4fe7ec51d00da03b4b
44+
branch: live-tests
45+
specs:
46+
stripe-ruby-mock (2.0.0)
47+
dante (>= 0.2.0)
48+
jimson-temp
49+
stripe (>= 1.15.0)
50+
4151
GEM
4252
remote: https://rubygems.org/
4353
remote: https://rails-assets.org/
@@ -106,6 +116,7 @@ GEM
106116
rack (>= 0.9.0)
107117
binding_of_caller (0.7.2)
108118
debug_inspector (>= 0.0.1)
119+
blankslate (3.1.3)
109120
bson (1.10.2)
110121
bson_ext (1.10.2)
111122
bson (~> 1.10.2)
@@ -176,6 +187,7 @@ GEM
176187
httparty (~> 0.10)
177188
json
178189
curb (0.8.6)
190+
dante (0.2.0)
179191
database_cleaner (1.3.0)
180192
debug_inspector (0.0.2)
181193
debugger-linecache (1.2.0)
@@ -195,6 +207,19 @@ GEM
195207
execjs
196208
eco-source (1.1.0.rc.1)
197209
ejs (1.1.1)
210+
elasticsearch (1.0.4)
211+
elasticsearch-api (= 1.0.4)
212+
elasticsearch-transport (= 1.0.4)
213+
elasticsearch-api (1.0.4)
214+
multi_json
215+
elasticsearch-model (0.1.4)
216+
activesupport (> 3)
217+
elasticsearch (> 0.4)
218+
hashie
219+
elasticsearch-rails (0.1.4)
220+
elasticsearch-transport (1.0.4)
221+
faraday
222+
multi_json
198223
em-http-request (1.1.2)
199224
addressable (>= 2.3.4)
200225
cookiejar
@@ -330,6 +355,11 @@ GEM
330355
jbuilder (2.1.3)
331356
activesupport (>= 3.0.0, < 5)
332357
multi_json (~> 1.2)
358+
jimson-temp (0.9.5)
359+
blankslate (>= 3.1.2)
360+
multi_json (~> 1.0)
361+
rack (~> 1.4)
362+
rest-client (~> 1.0)
333363
journey (1.0.4)
334364
jquery-rails (2.0.3)
335365
railties (>= 3.1.0, < 5.0)
@@ -758,6 +788,8 @@ DEPENDENCIES
758788
createsend
759789
database_cleaner
760790
dotenv-rails
791+
elasticsearch-model
792+
elasticsearch-rails
761793
ember-rails!
762794
fabrication-rails
763795
faraday (~> 0.8.1)
@@ -844,6 +876,7 @@ DEPENDENCIES
844876
spring-commands-rspec
845877
squeel (= 1.0.1)
846878
stripe!
879+
stripe-ruby-mock!
847880
strong_parameters
848881
syntax
849882
timecop

Rakefile

Lines changed: 280 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,283 @@ require 'rake'
44
Coderwall::Application.load_tasks
55

66
task default: :spec
7+
8+
namespace :team do
9+
task migrate: :environment do
10+
puts '--- Beginning team migration ---'
11+
success = true
12+
begin
13+
Team.each do |team|
14+
begin
15+
puts ">>> Migrating #{team.id}"
16+
TeamMigratorJob.new.perform(team.id.to_s)
17+
rescue => ex
18+
success = false
19+
puts "[#{team.id.to_s}] #{ex} >>\n#{ex.backtrace.join("\n ")}"
20+
end
21+
end
22+
ensure
23+
puts "--- #{success ? 'Successful' : 'Unsuccessful'} team migration ---"
24+
end
25+
end
26+
27+
#
28+
# IMPORTANT: pending_join_requests is a STRING array in Postgres but an INTEGER array in MongoDB.
29+
# IMPORTANT: pending_join_requests is an array of User#id values
30+
#
31+
32+
task verify: :environment do
33+
#ActiveRecord::Base.logger = nil
34+
#Mongoid.logger = nil
35+
#Moped.logger = nil
36+
37+
PgTeam.find_each(batch_size: 100) do |pg_team|
38+
begin
39+
mongo_id = pg_team.mongo_id
40+
mongo_team = Team.find(mongo_id)
41+
42+
# Ignoring:
43+
# - updated_at
44+
45+
puts 'TEAM'
46+
47+
neq(:slug, pg_team, mongo_team, false)
48+
49+
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)
50+
51+
%i(score size total mean median).each do |attr|
52+
neq_dec(attr, pg_team, mongo_team, false)
53+
end
54+
55+
%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|
56+
neq(attr, pg_team, mongo_team)
57+
end
58+
59+
# TODO: Account
60+
if mongo_team.account.present? && pg_team.account.blank?
61+
puts "account | pg:#{pg_team.id} | mongo:#{mongo_team.id}| The account was not migrated."
62+
end
63+
64+
if mongo_team.account.present? && pg_team.account.present?
65+
check_plans = %i(stripe_card_token stripe_customer_token admin_id).map do |attr|
66+
neq(attr, pg_team.account, mongo_team.account)
67+
end.any? { |x| !x }
68+
69+
# TODO: Plans
70+
if check_plans
71+
left = pg_team.account.plans.pluck(:id).sort
72+
right = mongo_team.account.plan_ids.sort
73+
74+
if left != right
75+
puts "account.plans | pg:#{pg_team.id} | mongo:#{mongo_team.id}| #{left} != #{right}"
76+
end
77+
end
78+
end
79+
80+
#puts 'LOCATIONS'
81+
82+
#pg_team_locations = pg_team.locations
83+
#mongo_team_locations = mongo_team.team_locations
84+
85+
#if mongo_team_locations.count != pg_team_locations.count
86+
#puts "locations | pg:#{pg_team.id} | mongo:#{mongo_team.id}| #{mongo_team_locations.count} != #{pg_team_locations.count}"
87+
#end
88+
89+
## Ignoring:
90+
## - points_of_interest
91+
#pg_team.locations.each do |pg_team_location|
92+
#mongo_team_location = mongo_team.team_locations.select { |tl| tl.name == pg_team_location.name }.first
93+
94+
#%i(address city country description name state_code).each do |attr|
95+
#neq(attr, pg_team_location, mongo_team_location, false)
96+
#end
97+
#end
98+
99+
100+
#puts 'LINKS'
101+
102+
pg_team_links = pg_team.links
103+
mongo_team_links = mongo_team.featured_links
104+
105+
if mongo_team_links.count != pg_team_links.count
106+
puts "links | pg:#{pg_team.id} | mongo:#{mongo_team.id}| #{mongo_team_links.count} != #{pg_team_links.count}"
107+
end
108+
109+
pg_team_links.each do |pg_team_link|
110+
mongo_team_link = mongo_team_links.select { |tl| tl.name == pg_team_link.name }.first
111+
112+
%i(url name).each do |attr|
113+
neq(attr, pg_team_link, mongo_team_link, false)
114+
end
115+
end
116+
117+
#puts 'MEMBERS'
118+
119+
if pg_team.members.count != mongo_team.team_members.count
120+
puts "members | pg:#{pg_team.id} | mongo:#{mongo_team.id}| #{pg_team.members.count} < #{mongo_team.team_members.count}"
121+
end
122+
123+
124+
#puts 'JOBS'
125+
126+
#pg_team.jobs.each do |pg_team_job|
127+
#mongo_team_job = Team.where(id: pg_team_job.team_document_id.to_s).first
128+
129+
#neq(:name, pg_team_job, mongo_team_job, false)
130+
#end
131+
132+
#puts 'FOLLOWERS'
133+
134+
pg_team.followers.each do |pg_team_follower|
135+
mongo_team_follower = Team.where(id: pg_team_follower.mongo_id.to_s).first
136+
# admins
137+
# editors
138+
%i(
139+
about
140+
achievement_count
141+
analytics
142+
benefit_description_1
143+
benefit_description_2
144+
benefit_description_3
145+
benefit_name_1
146+
benefit_name_2
147+
benefit_name_3
148+
big_image
149+
big_quote
150+
blog_feed
151+
branding
152+
country_id
153+
created_at
154+
endorsement_count
155+
facebook
156+
featured_banner_image
157+
featured_links_title
158+
github_organization_name
159+
headline
160+
hide_from_featured
161+
highlight_tags
162+
hiring_tagline
163+
interview_steps
164+
invited_emails
165+
link_to_careers_page
166+
location
167+
monthly_subscription
168+
name
169+
number_of_jobs_to_show
170+
office_photos
171+
organization_way
172+
organization_way_name
173+
organization_way_photo
174+
our_challenge
175+
paid_job_posts
176+
premium
177+
preview_code
178+
reason_description_1
179+
reason_description_2
180+
reason_description_3
181+
reason_name_1
182+
reason_name_2
183+
reason_name_3
184+
slug
185+
stack_list
186+
twitter
187+
upcoming_events
188+
upgraded_at
189+
valid_jobs
190+
website
191+
why_work_image
192+
your_impact
193+
youtube_url
194+
).each do |attr|
195+
neq(attr, pg_team_follower, mongo_team_follower, false)
196+
end
197+
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)
198+
199+
neq_string(:avatar, pg_team_follower, pg_team_follower.avatar.url, mongo_team_follower, mongo_team_follower.avatar.url, false)
200+
201+
%i(score size total mean median).each do |attr|
202+
neq_dec(attr, pg_team_follower, mongo_team_follower, false)
203+
end
204+
end
205+
206+
# TODO: Pending Requests
207+
end
208+
end
209+
end
210+
211+
def neq(attr, pg, mongo, fail_if_neq=true)
212+
left = pg.send(attr)
213+
right = mongo.send(attr)
214+
215+
if left != right
216+
puts "#{attr} | pg:#{pg.id} | mongo:#{mongo.id}| #{left} != #{right}"
217+
true
218+
else
219+
false
220+
end
221+
rescue => ex
222+
print_neq_error(ex)
223+
end
224+
225+
def neq_string(attr, pg, left, mongo, right, fail_if_neq=true)
226+
if left != right
227+
puts "#{attr} | pg:#{pg.id} | mongo:#{mongo.id}| #{left} != #{right}"
228+
true
229+
else
230+
false
231+
end
232+
rescue => ex
233+
print_neq_error(ex)
234+
end
235+
236+
def neq_dec(attr, pg, mongo, fail_if_neq=true)
237+
scale = 7
238+
239+
left = pg.send(attr).to_d.round(scale)
240+
right = mongo.send(attr).to_d.round(scale)
241+
242+
243+
if left != right
244+
puts "#{attr} | pg:#{pg.id} | mongo:#{mongo.id}| #{left} != #{right}"
245+
true
246+
else
247+
false
248+
end
249+
rescue => ex
250+
print_neq_error(ex)
251+
end
252+
253+
def print_neq_error(ex)
254+
puts '*'*80
255+
puts
256+
puts ex
257+
puts
258+
puts '-'*80
259+
puts
260+
ap ex.backtrace
261+
puts
262+
puts '*'*80
263+
264+
require 'pry'; binding.pry
265+
end
266+
267+
task counts: :environment do
268+
pg_team_count = PgTeam.count
269+
puts "PgTeam.count=#{pg_team_count}"
270+
team_count = Team.count
271+
puts "Team.count=#{team_count}"
272+
puts "Unmigrated teams count=#{(team_count - pg_team_count)}"
273+
end
274+
275+
276+
task unmigrated: :environment do
277+
unmigrated_teams = []
278+
279+
Team.all.each do |team|
280+
unmigrated_teams << team.id.to_s unless PgTeam.where(mongo_id: team.id.to_s).exists?
281+
end
282+
283+
puts "Unmigrated teams count=#{unmigrated_teams.count}"
284+
puts "Unmigrated Teams=%w(#{unmigrated_teams.join(' ')})"
285+
end
286+
end

0 commit comments

Comments
 (0)