在 MongoDB 中实施草稿和发布系统
Implement draft and publication system in MongoDB
我有一个 mongodb 数据库,其中包含 collection 个文档,大致如下:
// book document
{
_id: $oid,
userId: "..."
name: "name",
description: "description"
status: "draft"
// ...
}
// page document
{
_id: $oid,
bookId: "..."
name: "name",
description: "description"
// ...
}
一本书可以有几千页。每本书都有一个 status
属性,它可以具有 "draft"、"published" 或 "archived".
中的一种状态
一本 "draft" 本书可以从任何其他书籍创建,例如具有 "draft"、"published" 或 "archived" 状态。
每次创建新草稿时,都会创建一个与原书页数完全相同的新书文档。
任何 "draft" 书籍及其所有页面都可以独立于原始书籍及其页面进行编辑。这意味着对新草稿书或其任何页面的任何编辑都不会影响原书或其页面。
在设计中,书籍查询性能应优先于草稿创建性能,即查询一本书及其所有(分页)页面是最高性能优先级。
实现上述要求的最佳方法是什么?在此阶段可以对数据库模式进行任何修改。
这些是我考虑过的选项:
每当从现有图书创建新草稿时,克隆整本书及其所有页面。这将提供干净的草稿,可以独立完整地编辑并使用简单的 find
以最快的方式查询。缺点是 page
collection 的大小会随着草稿数量的增加而迅速增长,并且克隆书中的大部分页面将与原书中的版本完全相同。此外,创建草稿的时间会随着书中页数的增加而增加。
在 book
文档中添加 parentId
属性 以引用原始 book
并重复使用所有 un-modified 页parent。每次编辑页面时,都会克隆一个新页面,并将 bookId
设置为新草稿的 ID。这种方法将重用大部分 page
文档,但查询草稿书会复杂得多,因为我们需要遵循 parentId
链来查找所有修改过的页面和属于所有 parent 书籍(可以根据不同的草稿多次创建草稿)。创建草稿会非常快(只需克隆一本书),但查询时间会随着草稿的 parent 数量成比例增长。此外,当查询在不同 parent 中编辑过页面的草稿时,我们需要过滤掉所有旧页面版本并仅保留链中的最新版本。
您描述的两种方法的行为完全不同。在第一种(完全克隆)情况下,原始页面的更改仅适用于原始书籍。在第二种(分层)情况下,原始页面中的更改会自动传播到所有衍生草稿。我不会质疑哪个性能更好,因为这就像比较苹果和橙子。
考虑第三个选项 (copy-on-change) - 存储对书中页面的引用:
// book document
{
_id: $oid,
userId: "..."
name: "name",
description: "description"
status: "draft"
// ...
pages: [
$oid1,
$oid2,
$oid3,
....
]
}
创建新草稿就像克隆单个书籍文档一样简单。
用页面查询一本书是一个简单的查找聚合。
最昂贵的操作将是页面更改,如果您需要强大的数据完整性,可能需要 2 phase commit。
通过这种方法,您可以选择将更改传播到派生草稿,或将其保留在本地。如果稍后,您可能需要一个额外的内务处理步骤来删除孤立的页面。
我有一个 mongodb 数据库,其中包含 collection 个文档,大致如下:
// book document
{
_id: $oid,
userId: "..."
name: "name",
description: "description"
status: "draft"
// ...
}
// page document
{
_id: $oid,
bookId: "..."
name: "name",
description: "description"
// ...
}
一本书可以有几千页。每本书都有一个 status
属性,它可以具有 "draft"、"published" 或 "archived".
一本 "draft" 本书可以从任何其他书籍创建,例如具有 "draft"、"published" 或 "archived" 状态。
每次创建新草稿时,都会创建一个与原书页数完全相同的新书文档。
任何 "draft" 书籍及其所有页面都可以独立于原始书籍及其页面进行编辑。这意味着对新草稿书或其任何页面的任何编辑都不会影响原书或其页面。
在设计中,书籍查询性能应优先于草稿创建性能,即查询一本书及其所有(分页)页面是最高性能优先级。
实现上述要求的最佳方法是什么?在此阶段可以对数据库模式进行任何修改。
这些是我考虑过的选项:
每当从现有图书创建新草稿时,克隆整本书及其所有页面。这将提供干净的草稿,可以独立完整地编辑并使用简单的
find
以最快的方式查询。缺点是page
collection 的大小会随着草稿数量的增加而迅速增长,并且克隆书中的大部分页面将与原书中的版本完全相同。此外,创建草稿的时间会随着书中页数的增加而增加。在
book
文档中添加parentId
属性 以引用原始book
并重复使用所有 un-modified 页parent。每次编辑页面时,都会克隆一个新页面,并将bookId
设置为新草稿的 ID。这种方法将重用大部分page
文档,但查询草稿书会复杂得多,因为我们需要遵循parentId
链来查找所有修改过的页面和属于所有 parent 书籍(可以根据不同的草稿多次创建草稿)。创建草稿会非常快(只需克隆一本书),但查询时间会随着草稿的 parent 数量成比例增长。此外,当查询在不同 parent 中编辑过页面的草稿时,我们需要过滤掉所有旧页面版本并仅保留链中的最新版本。
您描述的两种方法的行为完全不同。在第一种(完全克隆)情况下,原始页面的更改仅适用于原始书籍。在第二种(分层)情况下,原始页面中的更改会自动传播到所有衍生草稿。我不会质疑哪个性能更好,因为这就像比较苹果和橙子。
考虑第三个选项 (copy-on-change) - 存储对书中页面的引用:
// book document
{
_id: $oid,
userId: "..."
name: "name",
description: "description"
status: "draft"
// ...
pages: [
$oid1,
$oid2,
$oid3,
....
]
}
创建新草稿就像克隆单个书籍文档一样简单。 用页面查询一本书是一个简单的查找聚合。
最昂贵的操作将是页面更改,如果您需要强大的数据完整性,可能需要 2 phase commit。
通过这种方法,您可以选择将更改传播到派生草稿,或将其保留在本地。如果稍后,您可能需要一个额外的内务处理步骤来删除孤立的页面。