如何在CouchDB上执行参数化查询

时间:2009-07-29 21:11:18

标签: couchdb

我想使用CouchDB为我存储一些数据,然后使用RESTful api调用来获取我需要的数据。我的数据库名为“test”,我的文档都有类似的结构,看起来像这样(其中hello_world是文档ID):

"hello_world" : {"id":123, "tags":["hello", "world"], "text":"Hello World"}
"foo_bar" :{"id":124, "tags":["foo", "bar"], "text":"Foo Bar"} 

我希望能够做的是让我的用户发送一个查询,例如:“给我所有包含”hello world“字样的文档,例如。我一直在玩视图但是看起来他们只允许我将这些值中的一个或多个移动到地图功能的“关键”部分。这使我有能力做这样的事情:

  

http://localhost:5984/test/_design/search/_view/search_view?key= “你好”

但这不允许我让我的用户指定他们的查询字符串。例如,如果他们搜索“hello world”怎么办?我必须做两个查询:一个用于“hello”,一个用于“world”然后我必须编写一堆javascript来组合结果,删除重复项等(YUCK!)。我真正想要的是能够做到这样的事情:

  

http://localhost:5984/test/_design/search/_view/search_view?term=“你好世界”

然后在views map / reduce函数中使用参数“hello world”来查找tags数组中同时包含“hello”和“world”的所有文档。 CouchDB甚至可以做到这一点吗?是否有另一种方法可以在我不想的视图中实现这一点?

3 个答案:

答案 0 :(得分:19)

CouchDB视图不支持分面搜索或全文搜索或结果交集。 couchdb-lucene插件可以让你做所有这些事情。

http://github.com/rnewson/couchdb-lucene/tree/master

答案 1 :(得分:2)

从技术上讲,如果您为每个文档发出文档标记的每组powerset作为键,则可以这样做。必须对键集元素进行排序,并且您的查询也必须查询所订购的标记。

function map(doc) {
  function powerset(array) { ... }

  powerset_of_tags = powerset(doc.tags)
  for(i in powerset_of_tags) {
    emit(powerset_of_tags[i], doc);
  }
}

对于文档{"hello_world" : {"id":123, "tags":["hello", "world"], "text":"Hello World"},它会发出:

{ key: [], doc: ... }
{ key: ['hello'], doc: ... }
{ key: ['world'], doc: ... }
{ key: ['hello', 'world'], doc: ... }

虽然这是可能的,但我认为这是一个相当尴尬的解决方案。我不想想象大量标签的视图的磁盘使用情况。我希望发出的密钥数量增长为2 ^ n。

答案 2 :(得分:0)

在后台,couchdb通过b树存储数据,因此您应该使用视图进行预处理,这种情况下的局限性是无法搜索正则表达式。或者,您可以按视图中键的前缀或后缀搜索。

注意:请勿使用emit(key,doc),它将克隆文档,您应使用emit(key,null)或emit(key)并在查询时添加“ include_docs = true”。

您可以使用自己的标签作为查询的键。

//查看功能

function (doc) {
  if (doc.type === "hello") {
    emit(doc);
  }
}

//芒果查询

db
.query(your_view_name,
      { startkey: startkey, endkey: endkey, include_docs: true });

注意:

endkey = startkey + "\uffff";
startkey = "h", "he", "hell"...

加:如果您不希望性能下降,请不要使用芒果查询来查询正则表达式。我通过查看功能解决了2分钟到2秒之间的性能问题。