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

时间:2010-07-22 16:46:03

标签: sorting filter nosql couchdb

我正在尝试将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 个答案:

答案 0 :(得分:47)

要在密钥中发送多个数据,您需要阅读Complex Keys。您最有可能最终emit()使用由类别和标记组成的数组的键。例如......

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

现在,当您查询?key=["fun", "couchdb"]时,您将获得标记为“couchdb”的有趣类别中的所有项目。或者,如果您想要有趣类别中的所有项目,无论其标记如何,那么您可以使用范围?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", {}, {}]

使用“couchdb”标记(降序)获取“有趣”类别中的所有内容:

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

使用couchdb标记(升序)获取有趣类别中的排名:

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

使用“couchdb”标记(降序)获取“fun”类别中的排名:

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

我希望这会有所帮助。复杂的键开始真正显示切片和切割数据时Map / Reduce的强大功能。

干杯。