【问题标题】:Need better JSON Schema to validate sparse matrix data object需要更好的 JSON Schema 来验证稀疏矩阵数据对象
【发布时间】:2017-04-03 03:59:15
【问题描述】:

我需要在 JavaScript 中验证复杂对象。

对象基于字典:

var dict = {'1':true,'2':true,'3':true};

对象存储矩阵对(通常不完整):

var obj = {'1':{
        '1': 'str1',
        '2': 'str2',
        '3': 'str3',
    },'2':{
        '1': 'str1',
        '2': 'str2',
    }
};

我使用 AJV 验证器制作验证架构。

架构要求:

  1. 1 级对象仅包含字典中的属性。
  2. 二级对象仅包含字典中的属性。
  3. 数据是字符串

生成架构:

var dict = {'1':true,'2':true,'3':true};

var subProperties = R.map(function(item){
  return {
    'type' : 'string',
    "minLength": 1,
  }
}, dict);
var root = {
  "type" : "object",
  "additionalProperties" : false
};
root.properties = R.map(function(item){
  return {
    "type" : "object",
    'properties' : subProperties,
    "additionalProperties" : false
  };
}, dict);

console.log(root)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ajv/4.9.0/ajv.min.js"></script>
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.22.1/ramda.min.js"></script>

此架构运行良好,但问题在于性能。当字典包含 200 个元素时,编译此模式需要 10 秒(验证快,编译慢)。此外,它不时抛出内存异常。是否可以制作更好的验证模式?

【问题讨论】:

    标签: javascript validation jsonschema ajv


    【解决方案1】:

    考虑到您要验证 40000 个属性,这里的内存异常并不奇怪。您的验证函数代码大小应该在 30Mb 左右。

    您可以使用我添加到 v5/6 proposals 并且在 ajv-keywords 包中提供的 propertyNames 关键字。

    var dict = ['1', '2', '3'];
    var schema = {
      type: 'object',
      propertyNames: { enum: dict },
      additionalProperties: {
        type: 'object',
        propertyNames: { enum: dict },
        additionalProperties: {
          type: 'string',
          minLength: 1
        }
      }
    };
    
    var ajv = require('ajv')();
    require('ajv-keywords')(ajv, 'propertyNames');
    
    var validate = ajv.compile(schema);
    

    这个架构很小,但作用相同。

    您可以使用当前标准版本中存在的 patternProperties 关键字(使用 es6 属性语法)来实现相同的目的:

    var names = '^(1|2|3)$';
    var schema = {
      type: 'object',
      additionalProperties: false,
      patternProperties: {
        [names]: {
          type: 'object',
          additionalProperties: false,
          patternProperties: {
            [names]: {
              type: 'string',
              minLength: 1
            }
          }
        }
      }
    };
    

    propertyNames 看起来更简单,我认为应该更快。

    【讨论】:

    • 非常有趣。您在propertyNames 的规范中有参考吗?甚至enum 都在示例中,但在specification 中看起来不存在。
    • 第一种方法很好,但我看不到在浏览器中添加 ajv-keywords 的方法。可能吗?第二种方式也很好,但实际上字典包含可以有任何符号的人名。所以制作正则表达式是可能的,但不幸的是不仅仅是 arr.join('|')。我也尝试使用“@ref”语法,但编译时间没有改变。这是否意味着 Ajv 多次编译相同的 @ref 子模式?
    • @Hurelu propertyNames 是一个提案(请参阅链接),它可用作 ajv 的自定义关键字,枚举在规范中 - json-schema.org/latest/…
    • 如果您使用 browserify/webpack,@NtsDK 应该不是问题。你只需要这个文件:github.com/epoberezkin/ajv-keywords/blob/master/keywords/…
    • 谢谢你,特别是。我将您的解决方案与 patternProperties 一起使用。它将编译时间从 10 秒减少到 1 秒。我不使用browserify/webpack,所以这个解决方案更适合我。
    【解决方案2】:

    通过映射items,结果不是1,而是N 架构(即,如果您有200 个项目,则创建200 个架构仅用于验证密钥)。

    另一种方法是使用 patternProperties 和一个巨大的 200 键长 RegExp 或更简单,只需手动验证对象。

    var dict = {'1':true,'2':true,'3':true};
    
    var monsterRegex = '^' + Object.keys(dict).join('|') + '$'
    
    var valSchema = {
      type: 'string',
      minLength: 1
    }
    var keySchema = {
      type: 'object',
      additionalProperties: false,
      patternProperties: {}
    }
    keySchema.patternProperties[monsterRegex] = valSchema
    
    var objSchema = {
      type: 'object',
      additionalProperties: false,
      patternProperties: {}
    }
    objSchema.patternProperties[monsterRegex] = keySchema
    
    console.log(objSchema)
    &lt;script src="https://cdnjs.cloudflare.com/ajax/libs/ajv/4.9.0/ajv.min.js"&gt;&lt;/script&gt;

    【讨论】:

    • 这种方式也不错,但实际上字典包含可以有任何符号的人名。所以制作 monsterRegex 是可能的,但不幸的是不仅仅是 arr.join('|')。是否可以自动转义所有正则表达式特价商品?
    • 在这种情况下,直接验证您的对象可能更简单,无需 JSON 模式。
    猜你喜欢
    • 2020-12-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-21
    • 2012-01-10
    • 1970-01-01
    • 2018-02-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多