gpt4 book ai didi

couchdb - 在 CouchDB 中对文档层次结构建模的最佳方法

转载 作者:行者123 更新时间:2023-12-02 09:53:07 25 4
gpt4 key购买 nike

我正在尝试在 CouchDB 中为层次结构建模以在我的系统中使用,这在概念上类似于博客。每篇博文至少属于一个类别,每个类别可以有很多篇文章。类别是分层的,这意味着如果帖子属于 CatB 在层次结构“ CatA -> CatB ”(“CatB 在 CatA 中)”中,它也属于 CatA .

用户必须能够快速找到类别中的所有帖子(及其所有子项)。

解决方案 1
post 类型的每个文档都包含一个“类别”数组,表示它在层次结构中的位置(参见 2)。

{
"_id": "8e7a440862347a22f4a1b2ca7f000e83",
"type": "post",
"author": "dexter",
"title": "Hello",
"category":["OO","Programming","C++"]
}

解决方案 2
帖子类型的每个文档都包含表示其在层次结构中的路径的“类别”字符串(请参阅 4 )。
{
"_id": "8e7a440862347a22f4a1b2ca7f000e83",
"type": "post",
"author": "dexter",
"title": "Hello",
"category": "OO/Programming/C++"
}

解决方案 3
帖子类型的每个文档都包含其父“类别”ID,表示其在层次结构中的路径(参见 3)。分层类别结构是通过链接的“类别”文档类型构建的。
{
"_id": "8e7a440862347a22f4a1b2ca7f000e83",
"type": "post",
"author": "dexter",
"title": "Hello",
"category_id": "3"
}

{
"_id": "1",
"type": "category",
"name": "OO"
}


{
"_id": "2",
"type": "category",
"name": "Programming",
"parent": "1"
}


{
"_id": "3",
"type": "category",
"name": "C++",
"parent": "2"
}

问题

在 CouchDB 中存储这种关系的最佳方式是什么?就磁盘空间、可扩展性和检索速度而言,最有效的解决方案是什么?

这种关系可以建模以考虑本地化的类别名称吗?

免责声明

我知道这个问题已经在 SO 上被问过几次了,但似乎没有明确的答案,也没有关于每个解决方案的利弊的答案。对不起,问题的长度:)

阅读到此

CouchDB - The Definitive Guide

Storing Hierarchical Data in CouchDB

Retrieving Hierarchical/Nested Data From CouchDB

Using CouchDB group_level for hierarchical data

最佳答案

这个问题没有正确的答案,因此缺乏确定的答案。这主要取决于您要优化的用途类型。

您声明 属于某个类别(及其子项)的文档的检索速度最重要 .前两个解决方案允许您创建一个 View ,该 View 可以多次发出博客文章,从叶子到根的链中的每个类别一次。因此,可以使用单个(因此快速)查询完成选择所有文档。第二种解决方案与第一种解决方案的唯一区别在于,您将类别“路径”的解析从插入文档的代码移动到组件中,然后再到 View 的 map 功能。我更喜欢第一个解决方案,因为它实现 map 功能更简单,而且更灵活(例如,它允许类别名称包含斜杠字符)。

在您的场景中,您可能还想创建一个简化 View ,计算每个类别的博客文章数量。这对于这两种解决方案中的任何一种都非常简单。使用拟合减少功能,可以使用单个请求检索每个类别中的帖子数量。

前两种解决方案的缺点是,将类别从一个父级重命名或移动到另一个父级需要更新每个文档。第三种解决方案允许在不接触文档的情况下进行。但是根据您的场景描述,我假设按类别检索非常频繁,而类别重命名/移动非常罕见。

解决方案 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”的附加类别,其 anchor 是“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 的 View 。在名为 _design/blog 的设计文档中具有以下 map 功能:
function (doc) {
if (doc.type == 'post') {
for (i in doc.category_anchestor_ids) {
emit([doc.category_anchestor_ids[i]], doc)
}
}
}

然后我们就可以得到 Programming中的所有帖子类别(其 ID "101")或其子类别之一使用 GET请求到以下 URL。
http://localhost:5984/so/_design/blog/_view/posts_by_category?reduce=false&key=["101"]

这将返回一个 View 结果,键设置为类别 ID,值设置为发布文档。相同的 View 还可用于获取所有类别的摘要列表以及该类别及其子项中的帖子数量。我们在 View 中添加以下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

这将返回一个缩小的 View 结果,键再次设置为类别 ID,值设置为每个类别中的帖子数。在此示例中,类别名称必须单独获取,但可以创建 View ,其中缩减 View 结果中的每一行都已包含类别名称。

关于couchdb - 在 CouchDB 中对文档层次结构建模的最佳方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16188519/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com