这个问题没有正确的答案,因此缺乏明确的答案。这主要取决于您要优化的使用类型。
您说属于某个类别(及其子类别)的文档的检索速度是最重要的。前两个解决方案允许您创建一个多次发出博客文章的视图,一次针对从叶到根的链中的每个类别。因此,可以使用单个(因此快速)查询来选择所有文档。第二种解决方案与第一种解决方案的唯一区别在于,您将类别“路径”的解析从将文档插入到视图的地图功能的代码中移动到组件中。我更喜欢第一种解决方案,因为它实现地图功能更简单,而且更灵活(例如,它允许类别名称包含斜线字符)。
在您的场景中,您可能还想创建一个精简视图,用于计算每个类别的博客文章数量。使用这些解决方案中的任何一个都非常简单。通过拟合缩减功能,可以使用单个请求检索每个类别中的帖子数量。
前两种解决方案的一个缺点是,将一个类别从一个父级重命名或移动到另一个父级需要更新每个文档。第三种解决方案允许在不接触文档的情况下进行。但是根据您对场景的描述,我假设按类别检索非常频繁,并且类别重命名/移动非常罕见。
解决方案 4我提出了第四个解决方案,其中博客文章文档包含对类别文档的引用,但仍然引用帖子类别的所有祖先。这允许在不触及博客文章的情况下重命名类别,并允许您使用类别存储其他元数据(例如类别名称或描述的翻译):
{
"_id": "8e7a440862347a22f4a1b2ca7f000e83",
"type": "post",
"author": "dexter",
"title": "Hello",
"category_ids": [3, 2, 1]
}
{
"_id": "1",
"type": "category",
"name": "OO"
}
{
"_id": "2",
"type": "category",
"name": "Programming",
"parent": "1"
}
{
"_id": "3",
"type": "category",
"name": "C++",
"parent": "2"
}
您仍然必须将类别的父级与类别一起存储,这是在帖子中复制数据,以允许遍历类别(例如,用于显示类别树以进行导航)。
您可以扩展此解决方案或您的任何解决方案,以允许将帖子分类为多个类别,或者一个类别具有多个父级。当一篇文章被分类为多个类别时,您需要将每个类别的祖先的并集存储在文章的文档中,同时保留作者选择的类别以允许它们与文章一起显示或稍后编辑。
让我们假设有一个名为“Ajax”的附加类别,其锚点为“JavaScript”、“Programming”和“OO”。为了简化下面的示例,我选择了类别的文档 ID 以等于类别的名称。
{
"_id": "8e7a440862347a22f4a1b2ca7f000e83",
"type": "post",
"author": "dexter",
"title": "Hello",
"category_ids": ["C++", "Ajax"],
"category_anchestor_ids": ["C++", "Programming", "OO", "Ajax", "JavaScript"]
}
要允许一个类别有多个父级,只需在一个类别中存储多个父级 ID。您需要在查找某个类别的所有祖先时消除重复项。
查看解决方案 4假设您想要获取特定类别的所有博客文章。我们将使用具有以下示例数据的数据库:
{ "_id": "100", "type": "category", "name": "OO" }
{ "_id": "101", "type": "category", "name": "Programming", "parent_id": "100" }
{ "_id": "102", "type": "category", "name": "C++", "parent_id": "101" }
{ "_id": "103", "type": "category", "name": "JavaScript", "parent_id": "101" }
{ "_id": "104", "type": "category", "name": "AJAX", "parent_id": "103" }
{ "_id": "200", "type": "post", "title": "OO Post", "category_id": "104", "category_anchestor_ids": ["100"] }
{ "_id": "201", "type": "post", "title": "Programming Post", "category_id": "101", "category_anchestor_ids": ["101", "100"] }
{ "_id": "202", "type": "post", "title": "C++ Post", "category_id": "102", "category_anchestor_ids": ["102", "101", "100"] }
{ "_id": "203", "type": "post", "title": "AJAX Post", "category_id": "104", "category_anchestor_ids": ["104", "103", "101", "100"] }
除此之外,我们使用posts_by_category
在设计文档中调用的视图,该视图_design/blog
通过以下映射函数调用:
function (doc) {
if (doc.type == 'post') {
for (i in doc.category_anchestor_ids) {
emit([doc.category_anchestor_ids[i]], doc)
}
}
}
然后我们可以使用对以下 URL 的请求来获取该Programming
类别(具有 ID "101"
)或其子类别之一中的所有帖子。GET
http://localhost:5984/so/_design/blog/_view/posts_by_category?reduce=false&key=["101"]
这将返回一个视图结果,其中键设置为类别 ID,值设置为发布文档。相同的视图还可用于获取所有类别的摘要列表以及该类别及其子类别中的帖子数量。我们在视图中添加以下reduce函数:
function (keys, values, rereduce) {
if (rereduce) {
return sum(values)
} else {
return values.length
}
}
然后我们使用以下 URL:
http://localhost:5984/so/_design/blog/_view/posts_by_category?group_level=1
这将返回一个缩减视图结果,其中键再次设置为类别 ID,值设置为每个类别中的帖子数。在此示例中,必须单独获取类别名称,但可以创建简化视图结果中的每一行都已包含类别名称的视图。