【问题标题】:Search, Sort and aggregate documents搜索、排序和聚合文档
【发布时间】:2020-03-25 05:26:11
【问题描述】:

我有一个包含两种不同文档类型的数据库:

{
  "id": "1",
  "type": "User",
  "username": "User 1"
}

以及具有以下结构的第二种文档类型:

{
  "id": "2",
  "type": "Asset",
  "name": "Asset one",
  "owner_id": "1"  //id of the user who owns the asset
}

我们需要显示现有资产的列表和所有者的姓名(并排)。我们能够通过使用视图和链接文档来实现这一点。问题是,现在我们需要能够进行视图不支持的搜索和排序。

我们尝试使用 CouchDB 实现的目标是否可行?我们可以使用搜索索引来做到这一点吗?

我们使用的是 CouchDB 2.3.1,但无法升级(至少目前如此)。

我需要搜索 username 和资产 name 并且还能够按这些字段排序。我们不需要功能齐全的搜索。 matches(不区分大小写)之类的就足够了。

示例中指定的id/owner_id,代表文档_id。用户不会拥有超过 10 个资产。正常情况下是 2/3 资产。

【问题讨论】:

  • 没有更多细节 - 例如。 什么您想要搜索和排序 - 没有人可以提供明确的答案。对于全文样式搜索等,请查看CouchDB-Lucene
  • 上述文档中的属性 id - 你的意思是要成为文档 _id 吗?
  • 另外,一个用户拥有的资产数量会不会很大,比如一百多个?
  • 嗨@RamblinRose。我已编辑问题以回答您的问题。非常感谢!
  • 资产名称会改变,还是不可变?

标签: couchdb


【解决方案1】:

在不了解资产文档的完整性质(例如生命周期、不变性等)的情况下,这可能会让您朝着积极的方向前进。问题似乎是需要来自两个文档的信息来生成有意义的视图,而这并没有发生。

假设资产名称是不可变的并且每个用户的资产数量很少,请考虑通过在用户文档中保留资产列表来解耦和非规范化 owner_id 关系。

例如,assets 属性包含拥有资产文档信息(_id、名称)的集合的用户文档:

{
  "_id": "1",
  "type": "User",
  "username": "User 1",
  "assets": [
    [
      "2",
      "Asset one"
    ],
    [
      "10",
      "Asset ten"
    ]
  ]
}

鉴于这种结构,资产文档相当薄

{
  "_id": "2", 
  "type": "Asset",
  "name": "Asset one"
}

我认为资产文档中的信息比提供的要多得多。

那么如何得到搜索和排序的结果呢?考虑具有以下映射功能的设计文档_design/user/_view/assets

function (doc) {
  if(doc.type === "User" && doc.assets) {
    for(var i = 0; i < doc.assets.length; i++) {
      /* emit user name, asset name, value as asset doc id */
      emit(doc.username + '/' + doc.assets[i][1], { _id: doc.assets[i][0] });
      /* emit asset name with leading /, value as User doc _id */
      emit('/' + doc.assets[i][1], { _id: doc._id })
    }
  }
}

假设数据库只有一个用户“用户 1”和两个资产文档“资产一”和“资产十”。

这个查询(使用 cUrl)

curl -G <db endpoint>/_design/user/_view/assets

产量

{
  "total_rows":4,"offset":0,"rows":[
    {"id":"1","key":"/Asset one","value":{"_id":"1"}},
    {"id":"1","key":"/Asset ten","value":{"_id":"1"}},
    {"id":"1","key":"User 1/Asset one","value":{"_id":"2"}},
    {"id":"1","key":"User 1/Asset ten","value":{"_id":"10"}}
  ]
}

不是很有趣,除了注意行是根据其key 升序返回的。要反转顺序,只需添加 descending=true 参数

curl -G <db endpoint>/_design/user/_view/assets?descending=true

产量

{
  "total_rows":4,"offset":0,"rows":[
    {"id":"1","key":"User 1/Asset ten","value":{"_id":"10"}},
    {"id":"1","key":"User 1/Asset one","value":{"_id":"2"}},
    {"id":"1","key":"/Asset ten","value":{"_id":"1"}},
    {"id":"1","key":"/Asset one","value":{"_id":"1"}}
  ]
}

现在事情变得很酷,那些很酷的东西是startkeyendkey

对于键的性质,我们可以查询“用户 1”的所有资产,并根据资产名称以排序方式返回资产文档,利用键中的斜线

 curl -G <db endpoint>/_design/user/_view/assets 
 -d "startkey="""User%201/"""" -d "endkey="""User%201/\uFFF0""""

注意我在 Windows 上,我们必须转义双引号 ;(

产量

{
  "total_rows":4,"offset":2,"rows":[
    {"id":"1","key":"User 1/Asset one","value":{"_id":"2"}},
    {"id":"1","key":"User 1/Asset ten","value":{"_id":"10"}}
  ]
}

这是一个前缀搜索。注意使用高位 unicode 字符 \uFFF0 作为终止符;我们要求视图中以“User 1/”开头的所有文档。

同样得到所有资产的排序列表

curl -G <db endpoint>/_design/user/_view/assets 
-d "startkey="""/"""" -d "endkey="""/\uFFF0""""

产量

{
  "total_rows":4,"offset":0,"rows":[
    {"id":"1","key":"/Asset one","value":{"_id":"1"}},
    {"id":"1","key":"/Asset ten","value":{"_id":"1"}}
  ]
}

由于 Asset 文档 _id 已发出,请使用 include_docs 获取 Asset 文档:

 curl -G <db endpoint>_design/user/_view/assets -d "include_docs=true"  
 -d "startkey="""User%201/"""" -d "endkey="""User%201/\uFFF0""""

产量

{
  "total_rows": 4,
  "offset": 2,
  "rows": [
    {
      "id": "1",
      "key": "User 1/Asset one",
      "value": {
        "_id": "2"
      },
      "doc": {
        "_id": "2",
        "_rev": "2-f4e78c52b04b77e4b5d2787c21053155",
        "type": "Asset",
        "name": "Asset one"
      }
    },
    {
      "id": "1",
      "key": "User 1/Asset ten",
      "value": {
        "_id": "10"
      },
      "doc": {
        "_id": "10",
        "_rev": "2-30cf9245b2f3e95f22a06cee6789d91d",
        "type": "Asset",
        "name": "Asset 10"
      }
    }
  ]
}

对于发出用户 _id 的资产也是如此。

警告

这里的主要缺点是删除 Asset 文档需要更新 User 文档;不是世界末日,但避免这种依赖会非常好。

鉴于资产与用户最初的 1-1 关系,完全摆脱资产文档并简单地将所有资产数据与用户文档一起存储可能是可行的,具体取决于您的使用情况,并大大降低了复杂性。

我希望以上内容能激发解决方案。祝你好运!

【讨论】:

    猜你喜欢
    • 2021-06-04
    • 1970-01-01
    • 1970-01-01
    • 2020-08-25
    • 2017-11-26
    • 2015-03-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多