2014-03-03 73 views
1

我一直在使用Ruby,但這是我第一次對數據庫做任何事情。我一直在玩MongoDB一段時間,在這一點上,我已經開始嘗試並填充一個簡單的數據庫。在Ruby中,如何使用嵌套數組作爲輸入來遞歸地填充Mongo數據庫?

這是我的問題。我有一個包含特定格式數據的文本文件。當我在閱讀文件時,該數據被存儲在嵌套的數組像這樣:

dataFile = ["sectionName", ["key1", "value1"], ["key2", "value2", ["key3", ["value3A", "value3B"]]] 

格式將始終是該陣列的第一個值是一個字符串,每個隨後的值是一個數組。每個數組都被格式化爲一個鍵/值對。但是,該值可以是一個字符串,兩個字符串的數組或具有自己的鍵/值數組對的一系列數組。在閱讀數據文件之前,我不知道有關數據文件的任何細節,只是它符合這些規則。

現在,這是我的問題。我想將它讀入保存這個基本結構的Mongo數據庫中。所以,舉例來說,如果我是用手工做到這一點,它應該是這樣的:

newDB = mongo_client.db("newDB") 
newCollection = newDB["dataFile1"] 
doc = {"section_name" => "sectionName", "key1" => "value1", "key2" => "value2", "key3" => ["value3A", "value3B"]} 
ID = newCollection.insert(doc) 

我知道必須有一個簡單的方法來做到這一點。到目前爲止,我一直在嘗試各種遞歸函數來解析數據,將其轉換爲mongo命令並嘗試填充我的數據庫。但它只是感覺笨重,就像有更好的方法。任何洞察這個問題將不勝感激。

回答

1

您爲變量dataFile給出的值不是有效數組,因爲它缺少結束方括號。

如果我們爲dataFile定義了一個有效的ruby代碼行,下面的代碼會產生你描述的散列。它使用mapwith_index訪問數組的每個元素,並將此數組轉換爲新的鍵/值散列數組。這個經過變換的散列數組是flatted,並使用inject方法轉換爲單個散列。

dataFile = ["sectionName", ["key1", "value1"], ["key2", "value2", ["key3", ["value3A", "value3B"]]]] 
puts dataFile.map.with_index { 
    |e, ix| 
    case ix 
    when 0 
    { "section_name" => e } 
    else 
    list = [] 
    list.push({ e[0] => e[1] }) 
    if(e.length > 2) 
     list.push(
     e[2..e.length-1].map {|p| 
      { p[0] => p[1] } 
     } 
    ) 
    end 
    list 
    end 
}.flatten.inject({ }) { 
    |accum, e| 
    key = e.keys.first 
    accum[ key ] = e[ key ] 
    accum 
}.inspect 

輸出看起來像:

{"section_name"=>"sectionName", "key1"=>"value1", "key2"=>"value2", "key3"=>["value3A", "value3B"]} 

對於輸入,看上去像這樣:

["sectionName", ["key1", "value1"], ["key2", "value2", ["key3", ["value3A", "value3B"]], ["key4", ["value4A", "value4B"]]], ["key5", ["value5A", "value5B"]]] 

我們會看到:

{"section_name"=>"sectionName", "key1"=>"value1", "key2"=>"value2", "key3"=>["value3A", "value3B"], "key4"=>["value4A", "value4B"], "key5"=>["value5A", "value5B"]} 

注意陣列 「KEY3」和「key4」,這就是我認爲的bei ng稱爲一系列數組。如果結構有未知深度數組的陣列,那麼我們需要一個不同的實現 - 也許使用一個數組來跟蹤位置,因爲程序遍歷這個任意嵌套的數組數組。

+0

gautamc, 非常感謝你。你太聰明瞭。但是,我確實有一個問題要問你。該解決方案可以平滑輸入數據。但是,我需要保持結構完整。那可能嗎? – user2800390

0

在下面的測試中,請找到兩個解決方案。 第一個轉換爲嵌套的散列,這是我認爲你想要的而不需要展平輸入數據。 第二個存儲與輸入中給定的鍵值對完全相同。 我選擇通過保留鍵值對來修復丟失的方括號。

這裏的主要信息是,雖然MongoDB的頂級數據結構是一個映射到Ruby Hash 的文檔,根據定義,它具有鍵值結構,但值可以是任何形狀,包括嵌套數組或哈希。 因此,我希望測試示例涵蓋了該範圍,表明您可以在MongoDB中匹配存儲以滿足您的需求。

test.rb

require 'mongo' 
require 'test/unit' 
require 'pp' 

class MyTest < Test::Unit::TestCase 
    def setup 
    @coll = Mongo::MongoClient.new['test']['test'] 
    @coll.remove 
    @dataFile = ["sectionName", ["key1", "value1"], ["key2", "value2"], ["key3", ["value3A", "value3B"]]] 
    @key, *@value = @dataFile 
    end 

    test "nested array data as hash value" do 
    input_doc = {@key => Hash[*@value.flatten(1)]} 
    @coll.insert(input_doc) 
    fetched_doc = @coll.find.first 
    assert_equal(input_doc[@key], fetched_doc[@key]) 
    puts "#{name} fetched hash value doc:" 
    pp fetched_doc 
    end 

    test "nested array data as array value" do 
    input_doc = {@key => @value} 
    @coll.insert(input_doc) 
    fetched_doc = @coll.find.first 
    assert_equal(input_doc[@key], fetched_doc[@key]) 
    puts "#{name} fetched array doc:" 
    pp fetched_doc 
    end 
end 

紅寶石test.rb

$ ruby test.rb 
Loaded suite test 
Started 
test: nested array data as array value(MyTest) fetched array doc: 
{"_id"=>BSON::ObjectId('5357d4ac7f11ba0678000001'), 
"sectionName"=> 
    [["key1", "value1"], ["key2", "value2"], ["key3", ["value3A", "value3B"]]]} 
.test: nested array data as hash value(MyTest) fetched hash value doc: 
{"_id"=>BSON::ObjectId('5357d4ac7f11ba0678000002'), 
"sectionName"=> 
    {"key1"=>"value1", "key2"=>"value2", "key3"=>["value3A", "value3B"]}} 
. 

Finished in 0.009493 seconds. 

2 tests, 2 assertions, 0 failures, 0 errors, 0 pendings, 0 omissions, 0 notifications 
100% passed 

210.68 tests/s, 210.68 assertions/s