2016-11-19 23 views
1

我需要在JavaScript中验证复杂的对象。需要更好的JSON模式来验证稀疏矩阵数据对象

对象基于词典:

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秒来编译该模式(验证速度快,编译速度慢)。而且它会随时间抛出内存异常。是否有可能制定更好的验证模式?

回答

2

鉴于您正在验证40000属性,因此内存异常并不令人惊讶。您的验证功能代码大小应该在30Mb左右。

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

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); 

这个模式很小,但也是一样的。

可以实现,在目前的标准版本存在(与ES6属性语法)同样使用patternProperties关键字:

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

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

+0

非常有趣。你在'propertyNames'的规范中有参考吗?即使'enum'也是遍布于例子中,但在[specification]中看不到(http://json-schema.org/latest/json-schema-validation.html)。 – Hurelu

+0

第一种方法很好,但我没有看到在浏览器中添加ajv关键字的方式。可能吗? 第二种方式也很好,但实际上字典中包含的人名可以有任何符号。所以使正则表达式是可能的,但不幸的是不只是arr.join('|')。 另外我尝试使用“@ref”语法,但编译时间不会改变。这是否意味着Ajv多次编译相同的@ref子模版? – NtsDK

+0

@Hurelu propertyNames是一个提案(请参阅链接),它可以作为ajv的自定义关键字,enum在spec中 - http://json-schema.org/latest/json-schema-validation.html#rfc。第5.20节 – esp

1

通过映射到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)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ajv/4.9.0/ajv.min.js"></script>

+0

这种方式也不错,但实际上字典中包含可以有任何符号的人的名字。所以制作monsterRegex是可能的,但不幸的是不仅仅是arr.join('|')。是否有可能自动查看所有正则表达式特殊功能? – NtsDK

+1

在这种情况下,直接验证对象可能更简单,不需要JSON模式。 – Hurelu