CouchDB上有哪三个实体(用户,文件夹,文件)的数据结构?

时间:2017-07-18 11:34:28

标签: json data-structures couchdb

我正在尝试在CouchDB中为类似Dropbox的场景建立一个“关系”:

  • 用户
  • 文件夹
  • 文件

到目前为止,我还在讨论是否引用或嵌入上述内容并且还没有解决权限问题。在我的场景中,我只想存储文件的路径,不想使用附件。这就是我所拥有的:

选项1(单独文件)

在这里,我将所有内容链接在一起,它(至少对我而言)似乎是一个RDBMS模型的副本,在使用NoSQL时不应该成为目标。

{   
    "id": "user1",
    "type": "user",
    "folders": [
        "folder1",
        "folder2"
    ]
}

{
    "id": "folder1",
    "type": "folder",
    "path": "\\user1\\pictures",
    "files": [
        "file1",
        "file2"
    ]
}

{
    "id": "file1",
    "type": "file",
    "name": "myDoc.txt",
}

选项2(单独的文件)

在此选项中,我会将用户文档保留原样,并将用户ID放入文件夹文档中以进行引用。

{   
    "id": "user1",
    "type": "user",
}

{
    "id": "folder1",
    "type": "folder",
    "path": "\\user1\\pictures",
    "owner" "user1",
    "files": [
        "file1",
        "file2"
    ]
}

{
    "id": "file1",
    "type": "file",
    "name": "myDoc.txt",
}

选项3(嵌入式文档)

与选项2类似,我在此处将删除第三个文档类型文件并将所有内容嵌入到文件夹文档中。我读到这只是一个选项,如果我不需要存储很多项目,我不知道用户将存储多少项目。

{   
    "id": "user1",
    "type": "user",
}

{
    "id": "folder1",
    "type": "folder",
    "path": "\\user1\\pictures",
    "owner" "user1",
    "files": [{
            "id": "file1",
            "type": "file",
            "name": "myDoc1.txt"
        }, {
            "id": "file2",
            "type": "file",
            "name": "myDoc2.txt"
        }
    ]
}

选项4

我也可以将所有内容都放在一个文档中,但在这种情况下,这没有任何意义。 JSON文档会在时间上变得很大,而这在性能/加载时间方面并不理想。

结论

对我来说,上述选项似乎都不适合我的场景,我很感激您在如何在CouchDB中设计正确的数据库架构方面的一些意见。或者上面的选项中的一个已经是一个好的开始,我只是没有看到它。

2 个答案:

答案 0 :(得分:1)

数据建模从应用程序将使用的查询开始。 如果您的查询是用户看到他/她的所有文件夹,并且打开文件夹会显示其下方的所有文档和子文件夹,则选项1非常适合查询。

但是,首先需要回答一个非常重要的问题,特别是对于CouchDB。这个数据库的大小是多少。如果您需要跨多个节点分区的数据库,那么性能将受到影响,可能达到DB无响应的程度。因为打开包含许多文档的文件夹意味着搜索每个分区。这是由于分区是由用户无法控制的ID的散列决定的。对于小型单节点(或非分区)DB,性能将很好。

选项2要求您在" owner"上构建索引,其原因与选项1相同。

选项3/4是一种非规范化,它解决了上述性能问题。如果文档很大并且经常更新,则存储的开销和压缩成本可能很高。您需要针对特定​​工作负载进行基准测试。

总之,如果您的目标数据库很大并且已经分区,那么就没有简单的答案。需要仔细的原型和基准标记。

答案 1 :(得分:1)

为了向您提供一个具体的想法,我将以某种方式为Dropbox克隆建模:

  • 共享:共享的根文件夹。没有必要对子文件夹进行建模,因为它们没有不同的权限。在这里,我可以设置文件夹的物理位置以及允许使用它们的用户。我预计每个用户只有几个共享,因此您可以将共享列表保留在内存中。
  • 文件:共享中的实际文件。根据您的使用情况,不需要将文件保存在数据库中,因为文件系统本身已经是一个很棒的文件数据库了!如果您需要哈希和重复数据删除文件(例如Dropbox这样做),那么您可以在CouchDB中创建一个缓存。

这将是文档结构:

{
  "_id": "share.pictures",
  "type": "share",
  "owner": "Alice",
  "writers": ["Bob", "Carl"],
  "readers": ["Dorie", "Eve", "Fred"],
  "rootPath": "\\user1\pictures"
},

{
  "_id": "file.2z32236e2sdwhatever",
  "type": "file",
  "path": ["vacations", "2017 maui"],
  "filename": "DSC1234.jpg",
  "size": 12356789,
  "hash": "1235a",
  "createdAt": "2017-07-29T15:03:20.000Z",
  "share": "share.pictures"
},

{
  "_id": "file.sdfwhatever",
  "type": "file",
  "path": ["vacations", "2015 alaska"],
  "filename": "DSC12345.jpg",
  "size": 11,
  "hash": "acd5a",
  "createdAt": "2017-07-29T15:03:20.000Z",
  "share": "share.pictures"
}

这样,您可以按共享和路径构建文件的CouchDB视图,并按文件夹查询:

function (doc) {
  if (doc.type === 'file') emit([doc.share].concat(doc.path), doc.size);
}

如果你愿意,你也可以添加一个只有_sum的reduce函数,并免费获得一个分层大小的计算器(好吧,差不多)!

假设你打电话给数据库' dropclone'并将视图添加到名为' dropclone'的设计文档中。使用视图名称'文件',您可以这样查询:

http://localhost:5984/dropclone/_design/dropclone/_view/files?key=["share.pictures","vacations"]

您的结果是123456800

有关     http://localhost:5984/dropclone/_design/dropclone/_view/files?key=[" share.pictures""休假"&安培;减少=假安培; include_docs =真

你会得到两个文件。

您还可以将整个共享名称和路径添加到_id中,因为这样您就可以直接通过已知路径访问每个文件。您仍然可以冗余地添加路径或将其保留,并将_id动态分割为其路径组件。

其他方法是:

  • 每个共享使用一个CouchDB数据库,并使用CouchDB的_security机制来管理访问。
  • 将文件拆分为块,散列它们并存储每个文件的块哈希值。这样,您就可以对整个文件系统进行虚拟化和重复数据删除。这就是Dropbox在幕后所做的事情,以节省存储空间。

你不应该做的一件事就是将文件本身存储到CouchDB中,这会很快变脏。几年前NPM必须经历这种情况,他们不得不在巨大的工程努力中摆脱这种模式。