我想在我的MongoDB Colleges集合中添加一个嵌入式Majors数组,如下所示:
{ "_id" : ObjectID("abc123"),
"code" : 123456,
"name" : "Stanford University",
"majors" :["Agriculture", "Business", "Computer Science"... ] }
我有一个CSV,基本上是一个CollegesMajors连接表(在SQL框架中)。它看起来像:
代码----- ---- MajorCode等级
123456 ---- 98765 --------- 2
123456 99999 ---- --------- 2
如何将这些专业(我可以将MajorCode首先翻译成实名)嵌入我的MongoDB学院系列中?
我必须有某种方式(伪代码):
db.colleges.update { match the code, update with array }
也许我需要先将CSV转换为JSON文件?
提前致谢!
更新<!/强>
这是我在尝试Tilo指令时遇到的错误 - 这可能与我对rails控制台不熟悉有关。它认为CSV.read指令正在加载一个零对象。
ruby-1.9.2-head :024 > csvAA = CSV.read( '/Users/administrator/dropbox/schoolninja/1College_Data/2009formatted/college_majors.csv' );
ruby-1.9.2-head :025 > headersA = csvAA.shift;
ruby-1.9.2-head :026 > csvAH = csvAA.map {|row| Hash[*headersA.zip(row).flatten] };
ruby-1.9.2-head :027 > csvAH.each do |rowH|
ruby-1.9.2-head :028 > c = College.find_by_code( rowH['Code'] )
ruby-1.9.2-head :029?> c.majors ||= []
ruby-1.9.2-head :030?> c.majors << ( rowH['title'] )
ruby-1.9.2-head :031?> c.save
ruby-1.9.2-head :032?> end
SyntaxError: (irb):24: unknown regexp options - adtratr
(irb):24: syntax error, unexpected tCONSTANT, expecting ')'
...opbox/schoolninja/1College_Data/2009formatted/college_majors...
... ^
(irb):24: syntax error, unexpected tIDENTIFIER, expecting $end
...nja/1College_Data/2009formatted/college_majors.csv );
... ^
from /Users/administrator/.rvm/gems/ruby-1.9.2-head/gems/railties-3.0.9/lib/rails/commands/console.rb:44:in `start'
from /Users/administrator/.rvm/gems/ruby-1.9.2-head/gems/railties-3.0.9/lib/rails/commands/console.rb:8:in `start'
from /Users/administrator/.rvm/gems/ruby-1.9.2-head/gems/railties-3.0.9/lib/rails/commands.rb:23:in `<top (required)>'
from script/rails:6:in `require'
from script/rails:6:in `<main>'
答案 0 :(得分:2)
如果您想从CSV文件的记录更新MongoDB,请查看新的Ruby Gem“ smarter_csv ”。它有许多有用的功能,包括大块文件的分块,并以块的形式返回结果作为哈希数组。
另见:
require 'smarter_csv'
filename = '/tmp/college_majors.csv'
# The :key_mapping renames one column and ignores the column "Level"
# Each line of the CSV-file is converted into a hash with keys: :major_code, :code
n = SmarterCSV.process(filename, {:chunk_size => 10,
:key_mapping => {:level => nil} }) do |chunk|
# We're passing a block in to process each resulting hash / row (block takes array of hashes).
# If the CSV-file is large, we can process it in parallel in chunks (using Resque Workers).
# For this we would extract the following block into a Resque worker and instead just create
# a new Resque job for each chunk.
chunk.each do |hash|
c = College.find_by_code( hash[:code] )
c.majors ||= []
c.majors << majorcode_to_name( hash[:major_code] )
c.save
end
end
假设您已经有一个方法majorcode_to_name():
require 'csv'
csvAA = CSV.read( csv_filename ) # returns an array of arrays
# => [["Code", "MajorCode", "Level"], ["123456", "98765", "2"], ["123456", "99999", "2"]]
headersA = csvAA.shift # extract the headers into an array
# => ["Code", "MajorCode", "Level"]
# turn the "array of arrays" which contain the CVS data, into an "Array of Hashes":
csvAH = csvAA.map {|row| Hash[*headersA.zip(row).flatten] }
# => [{"Code"=>"123456", "MajorCode"=>"98765", "Level"=>"2"}, {"Code"=>"123456", "MajorCode"=>"99999", "Level"=>"2"}]
csvAH.each do |rowH|
c = College.find_by_code( rowH['Code'] )
c.majors ||= [] # initialize as empty array if it doesn't exist
c.majors << majorcode_to_name( rowH['MajorCode'] )
c.save
end
如果您的CSV文件非常大,您可能需要稍微修改此代码,这样您就不必将整个数据读入RAM
require 'csv'
headersA = nil
CSV.foreach do |row|
if headersA.nil?
headersA = row
else
rowH = Hash[*headersA.zip(row).flatten]
c = College.find_by_code( rowH['Code'] )
c.majors ||= [] # initialize as empty array if it doesn't exist
c.majors << majorcode_to_name( rowH['MajorCode'] )
c.save
end
end
编辑: 我应该已经提到为什么我将CSV.read的结果转换为哈希数组。主要原因是使代码独立于CSV文件中标题的顺序 - 这使得代码更加健壮。 / p>