我有一个具有两种不同文档类型的数据库:
{
"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资产。
答案 0 :(得分: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"}}
]
}
现在这是凉爽的地方,那些凉爽的地方是startkey
和endkey
。
对于键的性质,我们可以查询“用户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 作为终止符;我们要求视图中所有以“用户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"}}
]
}
由于发出了资产文档_id,请使用include_docs
来获取资产文档:
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的资产也是如此。
注意事项
主要的缺点是删除资产文档需要更新用户文档;不是世界末日,但避免这种依赖将是非常好的。
鉴于资产与用户之间的原始1-1关系,完全摆脱资产文档,而仅将所有资产数据与用户文档一起存储可能是可行的,具体取决于您的用法,并且大大降低了复杂性。
我希望以上内容能启发解决方案。祝你好运!