2011-03-28 64 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} 
]}