2011-05-18 25 views
2

我一直在玩Couchbase服務器,現在只是試圖將我的本地數據庫複製到Cloudant,但是我的地圖/縮減函數對獲得了相互衝突的結果來構建一組唯一標記與其相關的項目...地圖/減少Couchbase和CloudAnt之間的差異

// map.js 
function(doc) { 
    if (doc.tags) { 
    for(var t in doc.tags) { 
     emit(doc.tags[t], doc._id); 
    } 
    } 
} 

// reduce.js 
function(key,values,rereduce) { 
    if (!rereduce) { 
    var res=[]; 
    for(var v in values) { 
     res.push(values[v]); 
    } 
    return res; 
    } else { 
    return values.length; 
    } 
} 

在雲底服務器這將返回JSON這樣的:

{"rows":[ 
{"key":"3d","value":["project1","project3","project8","project10"]}, 
{"key":"agents","value":["project2"]}, 
{"key":"fabrication","value":["project3","project5"]} 
]} 

這正是我想要的&預期。然而,在Cloudant副本相同的查詢,返回此:

{"rows":[ 
{"key":"3d","value":4}, 
{"key":"agents","value":1}, 
{"key":"fabrication","value":2} 
]} 

所以它在某種程度上只是返回值數組...高度混亂&很感激由幾μm& [R忍者任何見解的長度.. ;)

回答

2

我寧願減少/重新減少隱含,而不是取決於參數rereduce

function(doc) { // map 
    if (doc.tags) { 
    for(var t in doc.tags) { 
     emit(doc.tags[t], {id:doc._id, tag:doc.tags[t]}); 
    } 
    } 
} 

然後減少檢查它是否從相同標籤累積的文檔ID,或是否它只是計數不同的標籤。

function(keys, vals, rereduce) { 
    var initial_tag = vals[0].tag; 

    return vals.reduce(function(state, val) { 
    if(initial_tag && val.tag === initial_tag) { 
     // Accumulate ids which produced this tag. 
     var ids = state.ids; 
     if(!ids) 
     ids = [ state.id ]; // Build initial list from the state's id. 
     return { tag: val.tag, 
      , ids: ids.concat([val.id]) 
      }; 
    } else { 
     var state_count = state.ids ? state.ids.length : state; 
     var val_count = val.ids ? val.ids.length : val; 
     return state_count + val_count; 
    } 
    }) 
} 

(我沒有測試此代碼,但你的想法。只要tag值是一樣的,它不要緊它是否是一個降低或rereduce。一旦不同的標籤開始減少一起,它檢測到因爲tag值就會產生變化,所以在這一點上只是開始積累。

我以前也使用過這一招,雖然國際海事組織這是很不值得。

而且在您的具體情況 ,th是一個危險的減少功能。您正在建立一個廣泛的列表來查看所有有標籤的文檔。 CouchDB喜歡高列表,而不是胖列表。如果你想看到所有有標籤的文檔,你可以映射它們。

for(var a = 0; a < doc.tags.length; a++) { 
    emit(doc.tags[a], doc._id); 
} 

現在,您可以查詢/db/_design/app/_view/docs_by_tag?key="3d",你應該得到

{"total_rows":287,"offset":30,"rows":[ 
{"id":"project1","key":"3d","value":"project1"} 
{"id":"project3","key":"3d","value":"project3"} 
{"id":"project8","key":"3d","value":"project8"} 
{"id":"project10","key":"3d","value":"project10"} 
]} 
+0

謝謝大家對於我們所有的見解! (抱歉,我花了很長時間回覆,被拉走了)我已經設法解決了這個問題,但仍然覺得在couchdb中沒有任何調試功能的情況下,有時很難完全控制reduce部分。能夠看到中間結果可以更好地理解發生的事情。 – toxi 2011-07-22 02:41:33

4

看起來這正是您期望得到您的縮減功能的行爲。關鍵的部分是:

else { 
return values.length; 
} 

在Cloudant,rereduce總是被調用(因爲減少需要跨越多個碎片)在這種情況下,rereduce調用values.length,這將只返回的長度陣列。

+0

我看,但我怎麼能寫這樣的查詢,使其產生相同的結果(#1)這兩個平臺上?我現在不在乎(我確實:),我的減少功能並不完美,但我會假設一致的行爲... – toxi 2011-05-19 01:26:18

+0

+1,Alan。 Toxi,我建議你重寫,以便你可以「聞到」重新減少與最初的減少,而不檢查從沙發傳遞的參數。我之前已經完成了這個工作,所以我會嘗試作爲實際的答案,以便更好地進行格式化。 – JasonSmith 2011-05-19 01:43:27

+1

您只需要記住Cloudant _always_調用rereduce,因此如果您希望兩者一致,則需要使用rereduce子句來匹配您的reduce子句。作爲一個方面說明:CouchDB中的任何不重要的reduce函數都將使用rereduce,因此理解底層機制是個好主意。見例如http://wiki.apache.org/couchdb/Introduction_to_CouchDB_views#Reduce_vs_rereduce – Alan 2011-05-19 01:48:02