2011-03-28 41 views
8

有沒有辦法在CouchDB中執行以下操作?一種通過給定鍵返回唯一,不同值的方法?通過CouchDB中的鍵返回唯一值

SELECT DISTINCT field FROM table WHERE key="key1" 

'key1' => 'somevalue' 
'key1' => 'somevalue' 
'key2' => 'anotherval' 
'key2' => 'andanother' 
'key2' => 'andanother' 

例如:

http://localhost:5984/database/_design/designdoc/_view/distinctview?key= 「KEY1」 將返回[ 'someValue中']

http://localhost:5984/database/_design/designdoc/_view/distinctview?key= 「KEY2」 將返回[ 'anotherval', 'andanother']基於

+0

您可以加入關於你的文檔結構的更多細節? 'key1'和'key2'完全不同的字段?他們有某種相關性嗎? – 2011-03-28 14:21:24

+0

@Dominic - 我認爲它的意思是{「key」:「key1」,「value」:「somevalue」}和{「key」:「key2」,「value」:「othervalue」}而不是key1和key2是不同的領域,但我同意它是模糊的。 – 2011-03-30 15:55:49

+0

@Matt這或多或少是正確的,我們已經嘗試了非常類似的解決方案,但不得不應對「reduce_overflow_error」問題。 – wayoutmind 2011-04-01 11:54:20

回答

3

我在這裏看到的(如果需要,我會改變我的答案)key1key2看起來像獨立的字段,所以你需要2個獨立的視圖。

我創建了我的測試數據庫5個簡單的文件:

// I've left out fields like _id and _rev for the sake of simplicity 
{ "key1": "somevalue" } 
{ "key1": "somevalue" } 
{ "key2": "anotherval" } 
{ "key2": "andanother" } 
{ "key2": "andanother" } 

這裏有2次視圖的查詢您需要:

// view for key1 
function(doc) { 
    if (doc.key1) { 
    emit("key1", doc.key1); 
    } 
} 

// view for key2 
function(doc) { 
    if (doc.key2) { 
    emit("key2", doc.key2); 
    } 
} 

從那裏,你減少函數可以返回所有的值通過這樣做:

function (key, values) { 
    return values; 
} 

但是,您特別提到了不同值。由於JavaScript沒有用於數組的原生unique()方法,並且我們不能在視圖函數中使用CommonJS模塊,所以我們必須添加自己的邏輯。我只是複製了我在Google上發現的第一個array.unique()函數,您可以自己編寫一個更好的優化版本。

function (key, values, rereduce) { 
    var o = {}, i, l = values.length, r = []; 

    for (i = 0; i < l; i += 1) { 
    o[values[i]] = values[i]; 
    } 

    for (i in o) { 
    r.push(o[i]); 
    } 

    return r; 
} 

您將在這兩個視圖中使用相同的reduce函數。當你查詢任何這些視圖時,默認情況下它也會執行reduce。 (你需要明確地傳遞reduce=false讓你map功能的只是結果

這裏有你檢索使用上述map/reduce查詢結果集:(記得他們是2次獨立的查詢)

{"rows":[ 
    {"key":"key1", "value": ["somevalue"]} 
]} 

{"rows":[ 
    {"key": "key2", "value": ["anotherval", "andanother"]} 
]} 
+0

我試着創建一個簡單的返回'values'數組的reduce函數,但不幸couchdb用'reduce_overflow_error'響應。給出的理由是,「減少產量必須更快收縮......」。有什麼辦法可以解決這個問題嗎? – Xavi 2011-05-13 02:13:39

+1

你有3個選項。 1.你可以在你的couchdb配置中設置'reduce_limit = false'。 (最不利的選擇)2.您可以使用地圖功能,然後在您的客戶端執行減少操作(以獲取唯一值)。 (仍然不是很有利)3.將你的map函數重寫爲'emit(doc.key1,null);'並使用'group = true'(可能是最好的選擇) – 2011-05-13 14:24:01

+0

根據CouchDB指南,這是不正確的做事。話雖如此,我會喜歡這樣做。但是「減少產量必須更快速地收縮......」的錯誤真的會受到阻礙。如果reduce函數的輸出大小不是輸入大小的一半,則會引發此錯誤。此處的大小表示json編碼的字符串。如果輸入大小爲200字節,則忽略該約束。理論上可以通過在前端傳遞大量數據來滿足1/2約束條件來遊戲系統。對我來說似乎是一種浪費! – portforwardpodcast 2012-09-04 03:07:10

9

As suggested in the CouchDB definitive guide,你應該把你想成爲的唯一的密鑰值,然後查詢減少group=true功能。

例如,假設keyfield是場「鍵1」和「KEY2」和valuefield與值的字段,你的地圖功能可能是:

function(doc) { 
    // filter to get only the interesting documents: change as needed 
    if (doc.keyfield && doc.valuefield) { 
    /* 
    * This is the important stuff: 
    * 
    * - by putting both, the key and the value, in the emitted key, 
    * you can filter out duplicates 
    * (simply group the results on the full key); 
    * 
    * - as a bonus, by emitting 1 as the value, you get the number 
    * of duplicates by using the `_sum` reduce function. 
    */ 
    emit([doc.keyfield, doc.valuefield], 1); 
    } 
} 

和你減少功能可能是:

_sum 

然後用group=true&startkey=["key2"]&endkey=["key2",{}]查詢得到:

{"rows":[ 
{"key":["key2","anotherval"],"value":1}, 
{"key":["key2","andanother"],"value":2} 
]}