Cloudant 一对多函数
Cloudant 1 to many function
我刚开始使用 Cloudant,只是无法理解地图函数。我一直在摆弄下面的数据,但结果并不像我预期的那样。
关系是,一个用户可以拥有多辆车。一辆车属于一个用户。车辆“userId”是用户的密钥。有一点冗余,因为在用户中 _id 和 userId 是相同的,不需要稍后猜测。
无论如何,如何找到a/every个用户属于它的车辆?我通过反复试验得出的最接近的结果是显示每辆车的所有者,但我希望反过来,用户和属于它的车辆。我发现的所有示例都使用另一个文档来“连接”两个或多个文档,但我不需要这样做?
对正确方向的任何一点表示赞赏 - 我真的不知道。
function (doc) {
if (doc.$doctype == "vehicle")
{
emit(doc.userId, {_id: doc.userId});
}
}
编辑:越来越近了。我不确定我期待的是什么,但结果似乎有点 'messy'。 Row[0] 是用户文档,row[n > 0] 是车辆文档。我想当使用 startkey/endkey 时没问题,但没有结果有点混乱。
function (doc) {
if (doc.$doctype == 'user') {
emit([doc._id, 0], doc);
} else if (doc.$doctype == 'vehicle') {
emit([doc.userId, 1, doc._id], doc);
}
}
用户被描述为,
{
"_id": "user:10",
"firstname": “firstnamehere",
"secondname": “secondnamehere",
"userId": "user:10",
"$doctype": "user"
}
一辆车被描述为,
{
"_id": "vehicle:4002”,
“name”: “avehicle”,
"userId": "user:10",
"$doctype": "vehicle",
}
您的方向是正确的!您已经使用全局 ID 做到了这一点。以某种形式将文档类型作为 ID 的一部分是一个很好的主意,这样您以后就不会感到困惑(所有文档都在相同的 "pot" 中)。
以下是您当前解决方案的一些小问题(在开始您的实际问题之前):
不要将文档作为 emit(key, value)
中的值发出。您始终可以通过使用 include_docs=true
查询来查询属于视图行的文档。将文档作为视图值会大大增加视图索引。当不需要特定值时,使用emit(key, null)
.
您也不需要发射值中的 ID。无论如何,您将获得属于视图行的文档的 ID 作为该行的一部分。
查看排序规则
现在解决将车辆与其用户聚合的问题。你的基本模式是正确的。这个模式叫做 view collation,你可以阅读更多关于它的内容 in the CouchDB docs(忽略它在 "Couchapp" 部分)。
视图整理的技巧在于您 return 两种或多种类型的文档,但要确保它们的排序方式允许直接分组.因此,了解 CouchDB 如何对视图结果进行排序很重要。有关该内容的更多信息,请参阅 collation specification。理解视图排序规则的一个重要关键是具有数组键的行按键元素排序。因此,当两行具有相同的 key[0]
时,它们按 key[1]
排序。如果这也相等,则考虑 key[2]
,依此类推。
您的地图功能首先按用户 ID (key[0]
) 对用户和车辆进行分组。然后,您的地图函数使用 0
在键的第二个元素中排在 1
之前的事实,因此您的视图将包含以下内容:
- 用户 1
- 用户1的车辆
- 用户1的车辆
- 用户1的车辆
- 用户 2
- 用户 3
- 用户3的车辆
- 用户 4
- 等等
如您所见,用户的车辆立即跟随其用户。因此,您可以将此结果分组到聚合中,而无需执行昂贵的排序或查找操作。
注意,用户是按照ID排序的,用户内的车辆也是按照ID排序的。这是因为您使用了键数组中的 ID。
创建查询
如果不能按需查询,那视图就没有多大价值了。您拥有的视图支持以下查询:
- 获取所有用户及其车辆
- 获取一定范围内的用户及其车辆
- 获得单个用户及其车辆
- 获得一个没有车辆的用户(不过你也可以使用
_all_docs
视图)
"all users between user 1 and user 3 (inclusive) with their vehicles"
的示例查询
我们要查询一个范围,所以我们在查询中使用startkey
和endkey
:
startkey=["user:1", 0]
endkey=["user:3", 1, {}]
请注意使用 {}
作为标记值,这是必需的,以便结束键大于具有键 ["user:3", 1, (anyConceivableVehicleId)]
的任何行
我刚开始使用 Cloudant,只是无法理解地图函数。我一直在摆弄下面的数据,但结果并不像我预期的那样。
关系是,一个用户可以拥有多辆车。一辆车属于一个用户。车辆“userId”是用户的密钥。有一点冗余,因为在用户中 _id 和 userId 是相同的,不需要稍后猜测。
无论如何,如何找到a/every个用户属于它的车辆?我通过反复试验得出的最接近的结果是显示每辆车的所有者,但我希望反过来,用户和属于它的车辆。我发现的所有示例都使用另一个文档来“连接”两个或多个文档,但我不需要这样做?
对正确方向的任何一点表示赞赏 - 我真的不知道。
function (doc) {
if (doc.$doctype == "vehicle")
{
emit(doc.userId, {_id: doc.userId});
}
}
编辑:越来越近了。我不确定我期待的是什么,但结果似乎有点 'messy'。 Row[0] 是用户文档,row[n > 0] 是车辆文档。我想当使用 startkey/endkey 时没问题,但没有结果有点混乱。
function (doc) {
if (doc.$doctype == 'user') {
emit([doc._id, 0], doc);
} else if (doc.$doctype == 'vehicle') {
emit([doc.userId, 1, doc._id], doc);
}
}
用户被描述为,
{
"_id": "user:10",
"firstname": “firstnamehere",
"secondname": “secondnamehere",
"userId": "user:10",
"$doctype": "user"
}
一辆车被描述为,
{
"_id": "vehicle:4002”,
“name”: “avehicle”,
"userId": "user:10",
"$doctype": "vehicle",
}
您的方向是正确的!您已经使用全局 ID 做到了这一点。以某种形式将文档类型作为 ID 的一部分是一个很好的主意,这样您以后就不会感到困惑(所有文档都在相同的 "pot" 中)。
以下是您当前解决方案的一些小问题(在开始您的实际问题之前):
不要将文档作为
emit(key, value)
中的值发出。您始终可以通过使用include_docs=true
查询来查询属于视图行的文档。将文档作为视图值会大大增加视图索引。当不需要特定值时,使用emit(key, null)
.您也不需要发射值中的 ID。无论如何,您将获得属于视图行的文档的 ID 作为该行的一部分。
查看排序规则
现在解决将车辆与其用户聚合的问题。你的基本模式是正确的。这个模式叫做 view collation,你可以阅读更多关于它的内容 in the CouchDB docs(忽略它在 "Couchapp" 部分)。
视图整理的技巧在于您 return 两种或多种类型的文档,但要确保它们的排序方式允许直接分组.因此,了解 CouchDB 如何对视图结果进行排序很重要。有关该内容的更多信息,请参阅 collation specification。理解视图排序规则的一个重要关键是具有数组键的行按键元素排序。因此,当两行具有相同的 key[0]
时,它们按 key[1]
排序。如果这也相等,则考虑 key[2]
,依此类推。
您的地图功能首先按用户 ID (key[0]
) 对用户和车辆进行分组。然后,您的地图函数使用 0
在键的第二个元素中排在 1
之前的事实,因此您的视图将包含以下内容:
- 用户 1
- 用户1的车辆
- 用户1的车辆
- 用户1的车辆
- 用户 2
- 用户 3
- 用户3的车辆
- 用户 4
- 等等
如您所见,用户的车辆立即跟随其用户。因此,您可以将此结果分组到聚合中,而无需执行昂贵的排序或查找操作。
注意,用户是按照ID排序的,用户内的车辆也是按照ID排序的。这是因为您使用了键数组中的 ID。
创建查询
如果不能按需查询,那视图就没有多大价值了。您拥有的视图支持以下查询:
- 获取所有用户及其车辆
- 获取一定范围内的用户及其车辆
- 获得单个用户及其车辆
- 获得一个没有车辆的用户(不过你也可以使用
_all_docs
视图)
"all users between user 1 and user 3 (inclusive) with their vehicles"
的示例查询我们要查询一个范围,所以我们在查询中使用startkey
和endkey
:
startkey=["user:1", 0]
endkey=["user:3", 1, {}]
请注意使用 {}
作为标记值,这是必需的,以便结束键大于具有键 ["user:3", 1, (anyConceivableVehicleId)]