CouchDB如何在同一个视图中进行排序和过滤

35

我正在尝试在新应用中使用CouchDB,并且我需要创建一个视图,按多个字段排序并过滤多个字段。这是一个示例文档,为了节省输入,我省略了_id和_rev。

{
    "title": "My Document",
    "date": 1279816057,
    "ranking": 5,
    "category": "fun",
    "tags": [
        "couchdb",
        "technology"
    ],
}

我从文档中了解到,我可以轻松创建一个按排名等字段排序的视图。

function(doc) {
    emit(doc.ranking, doc);
}

我还学到可以很容易地按类别等字段进行过滤。

function(doc) {
    emit(doc.category, doc);
}

http://127.0.0.1:5984/database/_design/filter/_view/filter?key=%22fun%22

我的问题是,我需要同时完成许多这样的任务。我想根据类别和标签进行过滤。我应该能够过滤只有“ fun”类别和“ couchdb”标签的文档。我想按照排名降序,日期升序,标题字母顺序排序这些过滤结果。

我如何创建一个将所有排序和过滤组合在一起的视图?

1个回答

54

如果要在一个键中发出多个数据,您需要了解复杂键的知识。最可能的情况是使用emit()发出一个由类别和标签组成的数组作为键。例如...

function(doc) {
  for(var i = 0; i < doc.tags.length; i++)
    emit([doc.category, doc.tags[i]], doc);
}

现在,当你查询?key=["fun", "couchdb"]时,将会得到所有带有"couchdb"标签的"fun"类别的项。或者,如果你想要所有属于"fun"类别的项,无论它们是否带有标签,那么你可以查询一个范围:?startkey=["fun"]&endkey=["fun", {}]。只要记住,如果你的项有多个标签,它会在结果中出现多次(因为你用emit()一次性处理了每个标签)。

如果你想进一步按照评分、日期和标题排序,你需要向数组添加另外两个元素:一个整数和排名、日期或标题中的一个。请记住,你可以在一个映射函数中调用多次emit()。以下是一个示例映射函数...

function(doc) {
  for(var i = 0; i < doc.tags.length; i++)
  {
     emit([doc.category, doc.tags[i], 0, doc.ranking], doc);
     emit([doc.category, doc.tags[i], 1, doc.title], doc);
     emit([doc.category, doc.tags[i], 2, doc.date], doc);
  }
}
现在你的键结构为:["category", "tag", 0 ... 2, rank/title/date]。基本上,你将所有排名归为0,标题归为1,日期归为2。当然,你正在传输大量数据,因此你可以将这些分组中的每一个拆分成设计文档中的单独视图,或者仅返回文档的_id作为值 (emit([ ...], doc._id);)。
按升序获取“趣味”类别中具有“couchdb”标记的所有内容:
?startkey=["fun", "couchdb"]&endkey=["fun", "couchdb", {}, {}]

获取 "fun" 类别中带有 "couchdb" 标签的所有内容(按降序排列):

?startkey=["fun", "couchdb", {}, {}]&endkey=["fun", "couchdb"]&descending=true

获取只属于"couchdb"标签下的"fun"排名(升序):

?startkey=["fun", "couchdb", 0]&endkey=["fun", "couchdb", 0, {}]

获取只属于"couchdb"标签下的"fun"排名(降序):

?startkey=["fun", "couchdb", 0, {}]&endkey=["fun", "couchdb", 0]&descending=true

我希望这能有所帮助。复杂的键开始展现出Map/Reduce在切片和切块数据方面的强大。

谢谢。


谢谢,这真的很有帮助,但我需要更多的帮助。由于它一遍又一遍地发出相同的文档,我该如何让它只给我每个文档一次? - Apreche
1
除非您将每个分组拆分为自己的视图,否则无法实现。例如,/_design/articles/_view/byRanking、/_design/articles/_view/byDate等。如果您想在一个视图中保留所有内容,则必须在客户端中管理数据。或者,您可以按照我所说的仅返回文档的_id或null作为值,然后再进行第二次调用以获取文档。 - Sam Bisbee
哦,等等,不用了。我已经想通了。我觉得你可能有点误解我的意思。我想同时按照排名、日期和标题进行排序。在 SQL 中,应该是“order by ranking asc, date desc, title asc”。我可以通过只使用一个 emit 并使用 startkey 和 endkey 进行过滤来实现这一点,排序也会自动完成。谢谢! - Apreche
有点晚了,但如何处理部分字符串匹配?http://stackoverflow.com/questions/41608361/pouchdb-filtering-ordering-and-paging - user720491

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接