CouchDB文档建模原则

我有一个问题,我一直试图回答一段时间,但无法弄清楚:

您如何设计或分割CouchDB文档?

以博客文章为例。

实现它的半“关系”方法是创建一些对象:

  • 岗位
  • 用户
  • 评论
  • 标签
  • 片段
  • 这非常有道理。 但我正在尝试使用couchdb(出于所有原因,它很棒)来模拟相同的事情,这非常困难。

    大部分的博客文章都为您提供了一个简单的例子,说明如何做到这一点。 他们基本上以相同的方式划分它,但是说你可以为每个文档添加'任意'属性,这绝对是很好的。 所以你在CouchDB中有这样的东西:

  • 发布(在文档中使用标签和摘录“伪”模型)
  • 评论
  • 用户
  • 有些人甚至会说你可以将评论和用户放在那里,所以你可以这样做:

    
    post {
        id: 123412804910820
        title: "My Post"
        body: "Lots of Content"
        html: "<p>Lots of Content</p>"
        author: {
            name: "Lance"
            age: "23"
        }
        tags: ["sample", "post"]
        comments {
            comment {
                id: 93930414809
                body: "Interesting Post"
            } 
            comment {
                id: 19018301989
                body: "I agree"
            }
        }
    }
    

    这看起来非常好,很容易理解。 我也了解如何编写视图,从所有Post文档中提取评论,以便将它们导入评论模型中,与用户和标签相同。

    但后来我想,“为什么不把我的整个网站放在一个单一的文件?”:

    
    site {
        domain: "www.blog.com"
        owner: "me"
        pages {
            page {
                title: "Blog"
                posts {
                    post {
                        id: 123412804910820
                        title: "My Post"
                        body: "Lots of Content"
                        html: "<p>Lots of Content</p>"
                        author: {
                            name: "Lance"
                            age: "23"
                        }
                        tags: ["sample", "post"]
                        comments {
                            comment {
                                id: 93930414809
                                body: "Interesting Post"
                            } 
                            comment {
                                id: 19018301989
                                body: "I agree"
                            }
                        }
                    }
                    post {
                        id: 18091890192984
                        title: "Second Post"
                        ...
                    }
                }
            }
        }
    }
    

    你可以很容易地发表意见,找到你想要的东西。

    那么我的问题是,您如何确定何时将文档分成较小的文档或何时在文档之间建立“关系”?

    我认为它会更“面向对象”,并且更易于映射到值对象,如果它被如此分割:

    
    posts {
        post {
            id: 123412804910820
            title: "My Post"
            body: "Lots of Content"
            html: "<p>Lots of Content</p>"
            author_id: "Lance1231"
            tags: ["sample", "post"]
        }
    }
    authors {
        author {
            id: "Lance1231"
            name: "Lance"
            age: "23"
        }
    }
    comments {
        comment {
            id: "comment1"
            body: "Interesting Post"
            post_id: 123412804910820
        } 
        comment {
            id: "comment2"
            body: "I agree"
            post_id: 123412804910820
        }
    }
    

    ...但随后它开始更像一个关系数据库。 而且我经常会继承一些看起来像“整个网站在一个文件中”的东西,所以用关系模型化它更加困难。

    我已经阅读了很多关于如何/何时使用关系数据库和文档数据库的内容,因此这不是主要问题。 我更想知道的是,在CouchDB中建模数据时应用的最佳规则/原则是什么。

    另一个例子是XML文件/数据。 一些XML数据嵌套深度超过10个层次,我想用相同的客户端(例如Rails上的Ajax或Flex)可视化我将从ActiveRecord,CouchRest或任何其他对象关系映射器呈现JSON的情况。 有时我会得到整个站点结构的巨大XML文件,就像下面的文件一样,我需要将它映射到Value Objects以在我的Rails应用程序中使用,因此我不必编写其他序列化/反序列化数据的方式:

    
    <pages>
        <page>
            <subPages>
                <subPage>
                    <images>
                        <image>
                            <url/>
                        </image>
                    </images>
                </subPage>
            </subPages>
        </page>
    </pages>
    

    所以一般的CouchDB问题是:

  • 你用什么规则/原则来划分你的文件(关系等)?
  • 将整个网站放到一个文档中可以吗?
  • 如果是这样,你如何处理具有任意深度级别的序列化/反序列化文档(如上面的大json示例或xml示例)?
  • 或者你不把它们变成VO,你是否决定“这些嵌套到Object-Relational Map,所以我只能用原始XML / JSON方法访问它们”?
  • 非常感谢您的帮助,关于如何使用CouchDB分隔数据的问题,我很难说“这就是我应该从现在开始做的事情”。 我希望很快到达那里。

    我研究了以下网站/项目。

  • CouchDB中的分层数据
  • CouchDB Wiki
  • 沙发 - CouchDB应用程序
  • CouchDB权威指南
  • PeepCode CouchDB Screencast
  • CouchRest
  • CouchDB自述文件
  • ......但他们还没有回答这个问题。


    已经有一些很好的答案了,但我想添加一些更新的CouchDB功能来处理由viatropos描述的原始情况。

    分离文件的关键是可能存在冲突的地方(如前所述)。 您不应该在单个文档中将大量“纠结”文档集中在一起,因为您将获得完全无关更新的单个修订路径(例如,添加了对整个站点文档的修订版本的评论)。 管理各种较小文档之间的关系或连接起初可能会让人困惑,但CouchDB提供了多种选项,可将不同部分组合成单个响应。

    第一个重要的是视图整理。 当您将键/值对发送到map / reduce查询的结果中时,这些键将根据UTF-8归类进行排序(“a”在“b”之前)。 您还可以将地图/缩减中的复杂键作为JSON数组输出: ["a", "b", "c"] 。 这样做可以让你包含一个由数组键构成的“树”。 使用上面的示例,我们可以输出post_id,然后输出我们引用的事物类型,然后输出其ID(如果需要)。 如果我们将被引用文档的id输出到返回值中的对象中,我们可以使用'include_docs'查询参数将这些文档包含在map / reduce输出中:

    {"rows":[
      {"key":["123412804910820", "post"], "value":null},
      {"key":["123412804910820", "author", "Lance1231"], "value":{"_id":"Lance1231"}},
      {"key":["123412804910820", "comment", "comment1"], "value":{"_id":"comment1"}},
      {"key":["123412804910820", "comment", "comment2"], "value":{"_id":"comment2"}}
    ]}
    

    使用'?include_docs = true'请求相同的视图将添加一个'doc'键,该键将使用'value'对象中引用的'_id',或者如果'value'对象中不存在,它将使用从该行发出的文档的'_id'(在本例中是'post'文档)。 请注意,这些结果将包括一个引用源文件的'id'字段。 我把它留给空间和可读性。

    然后,我们可以使用'start_key'和'end_key'参数将结果过滤为单个帖子的数据:

    ?start_key=["123412804910820"]&end_key=["123412804910820", {}, {}]
    或者甚至专门提取某种类型的列表:
    ?start_key=["123412804910820", "comment"]&end_key=["123412804910820", "comment", {}]
    这些查询参数组合是可能的,因为空对象(“ {} ”)始终位于排序规则的底部,而null或“”总是位于最上方。

    在这些情况下,来自CouchDB的第二个有用的补充是_list函数。 这将允许您通过某种模板系统(如果您需要HTML,XML,CSV或其他类型)运行上述结果,或者如果您希望能够请求整个帖子的内容(包括作者和评论数据),并作为单个JSON文档返回,该文档与客户端/用户界面代码所需的内容相匹配。 这样做可以让你以这种方式请求文章的统一输出文档:

    /db/_design/app/_list/posts/unified??start_key=["123412804910820"]&end_key=["123412804910820", {}, {}]&include_docs=true
    您的_list函数(在本例中名为“统一”)将采用视图映射/缩减(在本例中为“posts”)的结果,并通过JavaScript函数运行它们,该函数将返回内容类型中的HTTP响应需要(JSON,HTML等)。

    结合这些事情,您可以将您的文档分成您认为有用的更高级别,冲突和复制“安全”的级别,然后在请求时根据需要重新组合它们。

    希望有所帮助。


    这本书说,如果我记得正确的话,直到“伤害”才能够正常化,同时牢记文件可能更新的频率。

  • 你用什么规则/原则来划分你的文件(关系等)?
  • 作为一个经验法则,我包括显示有关该项目的页面所需的所有数据。 换句话说,你可以在真实世界的一张纸上打印所有你会交给别人的东西。 例如,除了数字之外,股票报价单将包括公司名称,交易所,货币; 合同文件将包括交易对手的名称和地址,以及有关日期和签字的所有信息。 但是,不同日期的股票报价将形成单独的文件,单独的合约将形成单独的文件。

  • 将整个网站放到一个文档中可以吗?
  • 不,那会很愚蠢,因为:

  • 你将不得不在每次更新时阅读和编写整个网站(文档),这是非常低效的;
  • 你不会从任何视图缓存中受益。

  • 我知道这是一个古老的问题,但我遇到了它试图找出这个完全相同的问题的最佳方法。 Christopher Lenz撰写了一篇关于在CouchDB中建模“连接”的好方法。 我的一个结论是:“允许不冲突地添加相关数据的唯一方法是将相关数据放入单独的文档中。” 所以,为了简单起见,你需要倾向于“非规范化”。 但是由于在某些情况下写入冲突,你会遇到天生的障碍。

    在你的帖子和评论的例子中,如果单个帖子及其所有评论都存在于一个文档中,那么两个人试图同时发表评论(即针对该文档的同一修订版)将导致冲突。 在“单个文档中的整个站点”情况下,这会变得更糟。

    所以我认为经验法则会“直到它受到伤害才会反规范化”,但是它会“伤害”的一点是您很可能会针对文档的同一版本发布多个修改。

    链接地址: http://www.djcxy.com/p/26855.html

    上一篇: Principles for Modeling CouchDB Documents

    下一篇: Apache Felix shell with SSH