代码之家  ›  专栏  ›  技术社区  ›  Magiranu

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

  •  1
  • Magiranu  · 技术社区  · 8 年前

    • 用户
    • 文件夹

    到目前为止,我还在苦苦思索是引用还是嵌入上述内容,还没有解决权限问题。在我的场景中,我只想存储文件的路径,不想处理附件。以下是我所拥有的:

    选项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文档在时间上会变得很大,而这在性能/加载时间方面并不理想。

    结论

    2 回复  |  直到 8 年前
        1
  •  2
  •   Bernhard Gschwantner    7 年前

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

    • 共享:共享的根文件夹。无需对子文件夹建模,因为它们没有不同的权限。在这里,我可以设置文件夹的物理位置以及允许使用它们的用户。我希望每个用户只有几个共享,因此您可以将共享列表保存在内存中。

    这将是文件结构:

    {
      "_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"
    }
    

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

    如果需要,还可以添加一个reduce函数,只需 _sum 并免费获得一个层次大小计算器(好吧,几乎)!

    假设您调用了数据库“dropclone”,并将视图添加到名为“dropclone”的设计文档中,视图名为“files”,则您可以这样查询它:

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

    123456800 因此

    对于 http://localhost:5984/dropclone/_design/dropclone/_view/files?key=[ “共享图片”、“假期”]&reduce=false&include\u docs=true

    您还可以将整个共享名和路径添加到_id中,因为这样您就可以仅通过已知路径直接访问每个文件。您仍然可以冗余地添加路径或不添加路径,只需将\u id动态拆分为其路径组件。

    其他方法包括:

    • 每个共享使用一个CouchDB数据库,并使用CouchDB的\u安全机制来管理访问。
    • 将文件分割成块,对其进行散列,并存储每个文件的块散列。通过这种方式,您可以对整个文件系统进行虚拟化和重复数据消除。这就是Dropbox在幕后为节省存储空间所做的工作。

        2
  •  1
  •   user2400467    8 年前

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

    然而,有一个非常重要的问题需要首先回答,尤其是对于CouchDB。这就是数据库的大小。如果需要跨多个节点划分数据库,那么性能将受到影响,可能会导致数据库没有响应。因为打开一个包含许多文档的文件夹意味着搜索每个分区。这是因为分区是由用户无法控制的ID散列决定的。对于小型单节点(或非分区)DB,性能良好。

    选项3/4是一种非规范化,解决了上述性能问题。如果文档很大并且经常更新,则存储开销和压缩成本可能会很大。你需要为你的特定工作量设定基准。