2013-12-15 125 views
1

我正在研究MongoDB的mapReduce腳本,但我陷入了一個相當初學JavaScript的問題:我無法構建嵌套對象的路徑。設置是這樣的:在reduce步驟中,我有一個包含所有可能屬性(和一些示例值)的嵌套對象。構建嵌套對象的路徑

var result = { 
    computers: { 
     total: 12, 
     servers: { 
      total: 2, 
      os: { 
       unix: 2, 
       windows: 0 
      } 
     }, 
     clients: { 
      total: 10, 
      os: { 
       unix: 3, 
       windows: 7 
      } 
     } 
    } 
} 

從映射步驟我得到外來文檔類似如下:

var incoming = { 
    computers { 
     total: 1, 
     clients: { 
      total: 1, 
      os: { 
       windows: 1 
      } 
     } 
    } 
} 

傳入的文件是邏輯上的結果文檔的子集:元素的順序和可能的因素是相同的,他們只是不完整:一個可能只包含服務器數據,另一個可能只包含客戶端數據,第三個可能包含兩者等。

我想遍歷傳入文檔,併爲每個屬性添加它的值,以相應的適當ty在結果文件中。遞歸遍歷傳入文檔不是問題(我認爲),但構建路徑是。我想出了以下代碼:

var traverse = function(knots, path) { 
    for (var k in knots) { 
     if (knots[k] !== null && typeof(knots[k]) == "object") { 
      path = path[knots[k]]; 
      traverse(knots[k], path); 
     } 
     else { 
      // do something to get rid of the root-level incoming object 
      var rest = incoming.computers; 
      result[rest][knots[k]] += incoming[rest][knots[k]]; 
     } 
    } 
}; 

traverse(incoming.computers, incoming.computers); 

此腳本不起作用。我懷疑我嘗試連接路徑(第4行)並將它傳遞給加法運算符(第7行)的方式都被破壞了。
MongoDB響應「16722 TypeError:無法讀取未定義的屬性'1',但我不明白這一點。

編輯:改變了上面的代碼:現在用對象調用traverse [path](遵循Felix的提示)。後續問題是我不知道在else子句中構造路徑時如何擺脫'傳入'根對象。 似乎沒有辦法。至少MongoDB仍然與上面的錯誤相同。

+1

「路徑」的值究竟應該在哪一個中間步驟? –

+0

@FelixKling:你的意思是第4行?在我使用修改後的路徑遞歸調用函數之前,我將當前結添加到「路徑」。 –

+1

但'path'是一個字符串。你認爲訪問'path'中字符串的屬性'knots'會返回什麼結果? –

回答

0

我相信你想要的是

function clone(obj){ 
    if(obj == null || typeof(obj) != 'object') 
     return obj; 

    var temp = obj.constructor(); // changed 

    for(var key in obj) 
     temp[key] = clone(obj[key]); 
    return temp; 
} 

function update(oldData, newData){ 
    for (property in newData){ 
     if (oldData[property] !== undefined){ // existing path - needs to be updated 
      if (typeof(oldData[property]) === 'number'){ // element is number (total) - just add it 
       oldData[property] += newData[property]; 
      } else { // element is object - drill down 
       update(oldData[property], newData[property]); 
      } 
     } else { // new path - needs to be added 
      oldData[property] = clone(newData[property]); 
     } 
    } 
} 

它將處理添加新對象以及..

clone方法是從Most efficient way to clone an object?複製)


假設想要的結果是

result = { 
     computers: { 
      total: 13, 
      servers: { 
       total: 2, 
       os: { 
        unix: 2, 
        windows: 0 
       } 
      }, 
      clients: { 
       total: 11, 
       os: { 
        unix: 3, 
        windows: 8 
       } 
      } 
     } 
    } 
+0

這正是我想要的結果,我喜歡這個解決方案還可以幫助我構建初始結果對象。只有一個警告:它讓mongod意外退出:(我得到了同樣的'非法指令:4',當我拙劣地不存在已經存在的對象時,我總是得到這個'Illegal instruction:4',我試着恢復我的預先初始化結果對象並刪除了clone命令 - 但無濟於事 –

+0

發現問題:我的傳入文檔還包含一個字符串值的屬性。儘管我的代碼已經覆蓋了這種情況,但update()函數會將該屬性視爲字符串值,這當然是錯誤的。我不好意思,我以前沒有發現。我添加了另一個子句,現在一切都很棒:)非常感謝! –

+0

@tomlurge,很高興我可以幫助:) –