在 CouchDB 中使用 JSON 模式
Posted
技术标签:
【中文标题】在 CouchDB 中使用 JSON 模式【英文标题】:Work with JSON schema in CouchDB 【发布时间】:2015-02-18 05:35:58 【问题描述】:我会询问有关 CouchDB 中 JSON 示意图的良好实践。我现在使用纯 CouchDB 1.6.1。我在没有任何 couchapp 框架的情况下处理它(我知道这很有用,但我担心它将来会起作用)。
模式在 CouchDB 中的什么位置?作为常规文件?设计文件 ?或者也许将它们存储为文件?但是如果我要验证它们,尤其是在 validate_doc_update 函数中的服务器端,它们应该存储在设计文档中。
是否有任何库(最好是 javascript)在 CouchDB 和客户端(Web 浏览器)中工作?我可以生成 JSON 并自动验证它们的库?
我在思考如何向客户端发送数据,将它们存储在输入标签中,然后以某种方式收集并发送到服务器。也许将输入 id 设置为字段的路径,例如:
“地址”: “街道”:“xxx”, “编号”:“33”
在这种情况下,输入可能有 id = "Adress."Street",但我不知道这是一个好的解决方案。我应该从服务器发送架构并使用此架构构建 JSON 对象,但不知道如何(以防万一JSON 中的所有字段都有唯一的名称 - 包括层次结构)。
【问题讨论】:
【参考方案1】:我会告诉你,我是如何实现它的。
每个文档类型都有一个数据库,这允许我为每个数据库实现一个架构。
在每个数据库上,我都有一个 _design/schema
ddoc,其中包含一个架构和 validate_doc_update
函数来验证它。
我正在使用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);
希望这会有所帮助。
【讨论】:
【参考方案2】:在探索 CouchDB 在 Forms-over-Data 用例中的潜在优势时,您问了我多年来一直在问的同样的问题。
最初,我希望找到一种方法,可以基于相同的 JSON 架构定义和验证代码(服务器端和客户端)启用数据验证。事实证明,这不仅是可能的,而且还存在一些额外的优势。
CouchDB 中的 schema 放在哪里?作为常规文件?设计文件 ?或者也许将它们存储为文件?但是如果我要验证它们,尤其是在 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.json
、geo.json
、tel.json
等它在服务器 ddoc 中产生与以前使用单文件方法相同的 JSON 结构。但它更适合源代码管理。不仅较小的文件导致较少的合并冲突和更清晰的提交历史 - 还启用了通过子存储库(子模块)进行的模式依赖管理。
另一个想法是使用 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 函数中检测之前是否涉及更新处理程序的方法(也许其他人有?我很乐意阅读这样的解决方案。
在调查期间,我发现了同一架构的不同版本的问题。我应该如何管理?同一类型的所有文档都必须对同一架构版本有效(这意味着在几乎每个架构版本更改之前都需要进行 db 范围的数据迁移)? type 属性是否还应该包含版本号?等等
但是等等!如果文档的架构附加到文档本身会怎样?它:
将为文档内容提供兼容版本每个文档 可在 validate_doc_update 函数中访问(在oldDoc
中)
无需管理员访问权限即可复制(因为您需要 ddoc 更新)
将包含在客户端文档请求的每个响应中
这听起来很有趣,我觉得这是迄今为止最像 CouchDB 的方法。 说清楚 - 文档的架构附加到文档本身 em> - 表示将其存储在文档的属性中。作为附件的存储和将模式本身作为文档结构的使用都没有成功。
这种方法最敏感的时刻是文档的 CRUD 生命周期中的 C(创建)。可以想象有许多不同的解决方案来确保附加的模式是“正确和可接受的”。但这取决于您在特定项目中对这些术语的定义。
是否有任何库(最好是 JavaScript)在 CouchDB 和客户端(Web 浏览器)中工作?我可以生成 JSON 并自动验证它们的库?
我已经开始使用流行的JQuery Validation plugin 来实现。我可以使用模式作为配置并自动获得整洁的客户端验证。在服务器端,我将验证函数提取为 commonjs 模块。我希望以后能找到一种模块化的代码管理方式来防止代码重复。
事实证明,大多数现有的验证框架在模式匹配和单一属性验证方面都非常出色,但不能针对同一文档中的依赖值进行验证。此外,模式定义要求通常过于专有。对我来说,选择正确的模式定义的经验法则是:比起自己的实现,更喜欢标准化的定义(jsonschema.org、microdata、rdfa、hcard 等)。如果您保持结构和属性名称不变,您将需要更少的文档、更少的转换,并且有时您会自动获得与用户使用的外国软件(例如日历、地址簿等)的兼容性。如果您想为您的文档实现 html 演示文稿,您已经准备好以语义 web 和 SEO 方式进行。
最后——不想听起来傲慢——编写模式验证实现并不困难。也许您想阅读 JQuery Validation Plugin 的源代码 - 我相信您会发现像我一样令人惊讶的理解。在前端框架的流失率不断增加的时代,拥有自己的验证功能可能是最面向未来的方式。此外,我相信您应该对验证实现有 100% 的了解——它是您的应用程序的关键部分。如果你了解国外的实现——你也可以自己编写库。
好的。这是一个冗长的答案。对不起。如果有人读到最后并希望通过示例源代码查看详细的操作 - 点赞,我会写一篇博文并将 URI 作为评论附加。
【讨论】:
如果我对 POST to/the/doc/_id 的理解很好 - 在此选项中,您总是将更新函数中的 doc 设为 NULL。使用 PUT 将填充 doc 变量存在于数据库中的文档。如果您使用它的路径更新处理程序将调用:_design/doc/_update/updaterFunc -> 当更新函数将尝试将文档保存到数据库时,将运行 validateFunc。 “如果文档的架构附加到文档本身怎么办?” - 是否可以要求来自 _attachment 属性的文件?我曾经尝试过它,但它不会工作。但如果这可行,那么我应该找到一种方法来始终使用最新版本的模式(但我认为这并不难)。而且我应该记住不要用新的模式覆盖现有的模式,因为在数据库编译后我会丢失以前的模式。 无法访问 _attachments 服务器端。当模式永远不会改变时 - 然后将它们存储到 ddoc 中。【参考方案3】:也许最好的选择是使用json-schema。您在a lot of languages 中有实现。我在javascript中成功使用了tv4。
为了与沙发数据库集成,我认为最好的选择是定义 validation function 并使用 json-schema javascript 验证器。
【讨论】:
tv4.js 和 tv4.min.js 有什么区别?这是相同的代码,但针对所需空间进行了优化?它只包含验证模式,或者也包含生成? 相同的代码但被缩小了?是的。只有验证模式?是的。查看可用的 json-schema 工具:json-schema.org/implementations.html以上是关于在 CouchDB 中使用 JSON 模式的主要内容,如果未能解决你的问题,请参考以下文章
关于带有 couchDB 视图的“无效 JSON”的错误,但 json 很好