在不了解资产文档的完整性质(例如生命周期、不变性等)的情况下,这可能会让您朝着积极的方向前进。问题似乎是需要来自两个文档的信息来生成有意义的视图,而这并没有发生。
假设资产名称是不可变的并且每个用户的资产数量很少,请考虑通过在用户文档中保留资产列表来解耦和非规范化 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 作为终止符;我们要求视图中以“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 关系,完全摆脱资产文档并简单地将所有资产数据与用户文档一起存储可能是可行的,具体取决于您的使用情况,并大大降低了复杂性。
我希望以上内容能激发解决方案。祝你好运!