在CouchDB中使用JSON模式(schema)

6

我想询问在CouchDB中使用JSON schematics的好方法。我目前使用纯CouchDB 1.6.1。我没有使用任何couchapp框架(我知道这很有用,但我担心它将来会有功能上的问题)。

  • 在CouchDB中把模式放在哪里?作为常规文档?设计文档?还是存储为文件?但如果我要验证它们,特别是在validate_doc_update函数中进行服务器端验证,那么它们应该存储在设计文档中。

  • 是否有任何库(最好是JavaScript),可以在CouchDB和客户端(Web浏览器)中使用?我需要一个可以自动生成JSON并自动验证的库。

  • 我考虑如何将数据发送给客户端,将它们存储在输入标签中,然后以某种方式收集并发送到服务器。也许将输入ID设置为字段路径,例如:

    { "Adress" :{ "Street" : "xxx", "Nr" : "33" } }

在这种情况下,输入可以具有id = "Adress."Street",但我不知道这是否是一个好的解决方案。我应该从服务器发送模式,并使用此模式构建JSON对象,但不知道如何实现(如果JSON中的所有字段都具有唯一名称-包括层次结构)。

3个回答

11
您问的问题是我多年来探索在数据表单使用情况下CouchDB潜在优势时遇到的同样的问题。
最初,我的希望是找到一种方法,使基于相同的JSON模式定义和验证代码-服务器端和客户端的数据验证成为可能。结果证明,这不仅是可能的,而且还存在一些额外的优势。
在CouchDB中放置模式的位置?作为常规文档?设计文档?或者可能将它们存储为文件?但是如果我要验证它们,特别是在validate_doc_update函数中进行服务器端验证,它们应该存储在设计文档中。
您是正确的。设计文档(ddoc)也包括validate_doc_update函数以在文档更新之前执行验证,是放置模式的最常见位置。 validate_doc_update函数中的“this”是ddoc本身-可以从验证代码访问ddoc中包含的所有内容。
我已经开始将模式以JSON对象的形式存储在我的通用库属性/文件夹中,例如commonjs模块的lib/schemata.json。我的文档的type属性指定了文档更新验证应该获取的模式的键,例如type: 'adr' -> lib/schemata/adr。一个模式也可以根据属性引用其他模式 - 递归验证函数已经遍历到任何属性的末尾,无论嵌套属性来自什么类型。这在第一个项目中运行良好。
{
  "person": {
    "name": "/type/name",
    "adr": "/type/adr",
    ...
  },
  "name": {
    "forname": {
      "minlenght": 2,
      "maxlength": 42,
      ...
    },
    "surname": {
      ...
    }
  },
  "adr": {
    ...
  }
}

但是我想在另一个项目中使用该模式的子集。简单地复制它并添加/删除一些模式是短视的思考方式。如果像地址这样的通用架构存在错误并且需要在使用它的每个项目中进行更新呢?
此时,我的模式存储在仓库中的一个文件中(我使用erica作为ddocs的上传工具)。然后我意识到,当我将每个模式存储在单独的文件中,例如adr.jsongeo.jsontel.json等,它会产生与单文件方法相同的JSON结构在服务器ddoc中。但它更适合源代码管理。不仅较小的文件导致较少的合并冲突和更清晰的提交历史,而且通过子仓库(子模块)实现了模式依赖项管理。
另一个想法是将CouchDB本身用作模式存储和管理位置。但正如您自己提到的那样 - 模式必须在validate_doc_update函数中可访问。首先,我尝试了一种更新处理程序的方法 - 每个文档更新都必须通过验证更新处理程序,该处理程序自己从CouchDB中获取正确的模式:
POST /_design/validator/_update/doctype/person

function (schema, req) {
   ... //validate req.body against schema "person"
  return [req.body, {code: 202, headers: ...}]
}

但这种方法在嵌套模式下效果不佳。更糟糕的是,为了防止未经处理程序验证的文档更新,我不得不在CouchDB前面使用代理来隐藏直接内置的文档更新路径(例如POST到/the/doc/_id)。我没有找到一种方法来检测validate_doc_update函数是否在更新处理程序之前被涉及(也许有人有?我很高兴阅读这样的解决方案)。
在调查过程中,同一模式的不同版本问题出现在我的雷达上。我该如何管理它?必须所有相同类型的文档都有效地针对同一模式版本(这意味着需要在几乎每个模式版本更改之前进行全局数据迁移吗?)?类型属性是否也应包括版本号?等等。
但等等!如果文档的模式附加到文档本身呢?它:
- 将为每个文档提供兼容的版本 per doc - 可以在validate_doc_update函数中访问(在 oldDoc 中) - 可以在没有管理员访问权限的情况下复制(因为您需要ddoc更新) - 将包含在客户端文档请求的每个响应中 这听起来非常有趣,也感觉像是目前最符合CouchDB的方法。明确地说,文档的结构模式附加在文档本身上,意味着将其存储在文档的属性中。无论是作为附件存储还是使用模式本身作为文档结构都没有成功。
该方法最敏感的时刻是文档CRUD生命周期中的C(创建)。有许多不同的解决方案可想而知,以确保所附加的模式“正确且可接受”。但这取决于您在特定项目中对这些术语的定义。

是否有库(最好是JavaScript)适用于CouchDB和客户端(Web浏览器)?我可以使用该库生成JSON并自动验证吗?

我开始使用流行的JQuery Validation插件进行实现。我可以将模式用作配置,并自动获得整洁的客户端验证。在服务器端,我已经将验证函数提取为commonjs模块。我希望以后能找到一种模块化的代码管理方式,以避免代码重复。
现有的大多数验证框架在模式匹配和单属性验证方面非常出色,但不能够对同一文档中的相关值进行验证。此外,模式定义要求通常过于专有。对我来说,选择正确的模式定义的经验法则是:优先选择标准化定义(jsonschema.org、microdata、rdfa、hcard等),而不是自己实现。如果保留结构和属性名称,您将需要更少的文档、更少的转换,并且有时会自动与用户使用的外部软件(例如日历、地址簿等)兼容。如果您想为文档实现HTML演示文稿,那么您可以以语义Web和SEO方式做好准备。
最后,不想显得自大,编写模式验证实现并不困难。也许您想阅读JQuery Validation插件的源代码,我相信您会像我一样感到惊人的易懂。在前端框架的更新速度不断加快的时代,拥有自己的验证函数可能是最具未来性的方式。此外,我认为您应该对验证实现有100%的理解-这是应用程序的关键部分。如果您理解了外部实现,也可以自己编写库。

好的,这是一个很长的回答。抱歉。如果有人看完并想看到详细的实例源代码 - 给我点赞,我会写一篇博客文章并将 URI 附加为评论。


如果我对POST到/the/doc/_id的理解是正确的,那么在这种情况下,在更新函数中始终会将doc作为NULL获取。使用PUT将填充数据库中已存在的文档中的doc变量。如果您使用路径_design/doc/_update/updaterFunc,则将调用更新处理程序->当更新函数尝试将文档保存到数据库时,validateFunc将运行。 - InnerWorld
如果文档的模式附加到文档本身,那么从“_attachment”属性中请求文件是否可行?我尝试过一些时间,但它不起作用。但是,如果这样做可以实现,那么我应该找到一种始终使用最新版本模式的方法(但我认为这并不难)。我还应该记住不要用新模式覆盖已有的模式,因为在数据库压缩后我会丢失以前的模式。 - InnerWorld
无法在服务器端访问_attachments。当模式从不改变时 - 将其存储到ddoc中。 - Ingo Radatz

10

我会告诉你,我是如何实现它的。

  1. 我每种文档类型都有一个数据库,这使得我可以为每个数据库实现一个模式(schema)。

  2. 在每个数据库上,我都有一个名为_design/schema的ddoc(document design),其中包含一个模式和用于验证它的validate_doc_update函数。

  3. 我正在使用Tiny Validator (for v4 JSON Schema),它直接包含在_design/schema ddoc中。


_design/schema ddoc看起来像这样:

{
  "_id": "_design/schema",
  "libs": {
    "tv4": // Code from https://raw.githubusercontent.com/geraintluff/tv4/master/tv4.min.js
  },
  "validate_doc_update": "..."
  "schema": {
    "title": "Blog",
    "description": "A document containing a single blog post.",
    "type": "object",
    "required": ["title", "body"],
    "properties": {
      "_id": {
        "type": "string"
      },
      "_rev": {
        "type": "string"
      },
      "title": {
        "type": "string"
      },
      "body": {
        "type": "string"
      }
    }
  }
}

validate_doc_update函数看起来像这样:

function(newDoc) {
  if (newDoc['_deleted']) return;

  var tv4 = require('libs/tv4');

  if (!tv4.validate(newDoc, this.schema)) {
    throw({forbidden: tv4.error.message + ' -> ' + tv4.error.dataPath});
  }
}
希望这有所帮助。

0

也许最好的选择是使用json-schema。你可以在很多语言中找到实现方式。我曾经在javascript中成功地使用tv4

为了与couch db集成,我认为最好的选择是定义一个验证函数并利用json-schema javascript验证器。


tv4.js和tv4.min.js有什么区别?这是相同的代码,但是否经过优化以减少所需空间?它只包含验证模式还是生成模式也包括在内? - InnerWorld
同样的代码但是被压缩了吗?是的。仅验证模式吗?是的。查看可用的JSON架构工具:http://json-schema.org/implementations.html - jruizaranguren

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接