My Foo documents have a CustomData collection used to add user-configurable properties.
Sometimes, when I create those properties, I'm need to add them with a default value for indexing purposes.
This is what I'm trying to use for that purpose:
DatabaseCommands.UpdateByIndex(
"dynamic/Foos",
new IndexQuery(),
new[]
{
new PatchRequest
{
Name = "CustomData",
Type =Â PatchCommandType.Add,
Value = RavenJObject.FromObject(new
{
Value = false,
Bar = new { Baz = "Qux"}
})
}
});
This generates the following HTTP request:
PATCH /databases/MyDb/bulk_docs/dynamic/Foos?&pageSize=128&allowStale=False
[
{
"Type": "Add",
"Value": {
"Value": false,
"Bar": {
"Baz": "Qux"
}
},
"Name": "CustomData"
}
]
And this returns 200 OK, but no documents are modified.
It looks like the problem is the usage of dynamic indexes.
Switching to a persistent index solved the problem.
Related
I have a SQL Server stored procedure that has an ID parameter and returns a string in JSON format that is needed in the Angular app.
Here is a sample of the JSON needed:
[
{
"type": "date",
"name": "asofdate",
"ui":
{
"label": "As Of Date",
"placeholder": "Enter a date"
},
"validators": { "required": "true" }
},
{
"type": "select",
"name": "scope",
"ui": { "label": "Scope", "placeholder": "Select a scope" },
"validators": { "required": "true" },
"source": [
{ "value": 1, "text": "ABC" },
{ "value": 2, "text": "CDE" },
{ "value": 3, "text": "FGI" }
]
}
]
Here is a what the result of running the stored procedure looks like:
When I run the Web API passing the ID parameter to the stored procedure, I would like to capture the response as a JSON object to be used in the Angular app.
But the Web API is returning this:
[
{
"jsonResponse": "[
{
\"type\":\"date\",
\"name\":\"asofdate\",
\"ui\":{\"label\":\"As Of Date\",\"placeholder\":\"Enter a date\"},
\"validators\":{\"required\":\"true\"}
}
,
{
\"type\":\"select\",
\"name\":\"scope\",
\"ui\":{\"label\":\"Scope\",\"placeholder\":\"Select a scope\"},
\"validators\":{\"required\":\"true\"},
\"source\":[{\"value\":1,\"text\":\"ABC\"},{\"value\":2,\"text\":\"DEF\"},{\"value\":3,\"text\":\"GHI\"}]}
}
]
Is there a way to get the JSON response from the Web API without all the "\" and without:
{
"jsonResponse": "
so that it matches the sample above?
Here is the code from the Web API:
[HttpGet("{ReportID}")]
public async Task<ActionResult<IEnumerable<usp_ReportParameterResult>>> GetReportParameters(int ReportID)
{
if (_context.usp_ReportParameterAsync == null)
{
return NotFound();
}
var op = new OutputParameter<int>();
var JSONresponse = await _context.usp_ReportParameterAsync(ReportID, op);
if (JSONresponse == null)
{
return NotFound();
}
return JSONresponse;
}
The stored procedure uses JSON_QUERY and JSON PATH to create the needed nested arrays.
So, in the angular code I have the following hard-coded:
TESTDATA:any[] = [
{
type:'text',
name:'firstName',
validators:{
required:true
},
ui:{label:'First Name',placeholder:'Enter Your First Name'}
}
,
{
"type":"date",
"name":"asofdate",
"ui":{"label":"****As Of Date","placeholder":"Enter a date","class":["date-picker-wrapper"]},
"validators":{"required":"true"}
}
]
What I need is instead of this data being hrad-coded it is being dynamically generated from a Web API.
The hard-coded data looks like the following from browser debug:
[![enter image description here][2]][2]
From the web api data looks like the following:
It is not an array like the TESTDATA. Is the a way to get response from web api into an array format as required?
Actually, easiest solution was to remove the backlashes in the Angular app by simply doing the following:
for (let item of this.formattedJSON) {
item.ui = JSON.parse(item.ui);
item.validators = JSON.parse(item.validators);
}
I'm using AJV (Another Json schema validator) on NodeJs.
I've the following schema
var schema = {
"$id": "testSchema.json",
"type": "object",
"$schema": "http://json-schema.org/draft-06/schema#",
"additionalProperties": false,
"properties": {
"userId": {
"type": "integer"
},
"userName": {
"type": "string"
},
"uniqueID": {
"type": "integer"
}
}
}
I need to overwrite unqiueID property by a value that I could somehow pass to Json schema or AJV.
I think the above can be done using AJV addKeyword method, tried using it but failed because I don't know how to manipulate (and return) data value from AJV custom keywords.
Is possible to modify data with AJV ? or are there any other possible ways to do it??
Thank you!
You can create a custom keyword with function that will do whatever your want to data.
var Ajv = require('ajv');
var ajv = new Ajv({allErrors: true});
ajv.addKeyword('my_id_rewrite', {
type: 'object',
compile: function (sch, parentSchema) {
return function (data) {
console.log(data)
data['my_id']=parentSchema.my_id_rewrite;
return true;
}
}
});
var schema = { "my_id_rewrite": 2 };
var validate = ajv.compile(schema);
o = {"my_id":1}
console.log(validate(o)); // true
console.log(o); // Object {my_id: 2}
https://runkit.com/embed/cxg0vwqazre3
The required field in JSON Schema
JSON Schema features the properties, required and additionalProperties fields. For example,
{
"type": "object",
"properties": {
"elephant": {"type": "string"},
"giraffe": {"type": "string"},
"polarBear": {"type": "string"}
},
"required": [
"elephant",
"giraffe",
"polarBear"
],
"additionalProperties": false
}
Will validate JSON objects like:
{
"elephant": "Johnny",
"giraffe": "Jimmy",
"polarBear": "George"
}
But will fail if the list of properties is not exactly elephant, giraffe, polarBear.
The problem
I often copy-paste the list of properties to the list of required, and suffer from annoying bugs when the lists don't match due to typos and other silly errors.
Is there a shorter way to denote that all properties are required, without explicitly naming them?
You can just use the "minProperties" property instead of explicity naming all the fields.
{
"type": "object",
"properties": {
"elephant": {"type": "string"},
"giraffe": {"type": "string"},
"polarBear": {"type": "string"}
},
"additionalProperties": false,
"minProperties": 3
}
I doubt there exists a way to specify required properties other than explicitly name them in required array.
But if you encounter this issue very often I would suggest you to write a small script that post-process your json-schema and add automatically the required array for all defined objects.
The script just need to traverse the json-schema tree, and at each level, if a "properties" keyword is found, add a "required" keyword with all defined keys contained in properties at the same level.
Let the machines do the bore stuff.
I do this in code with a one-liner, for instance, if I want to use required for insert in a DB, but only want to validate against the schema when performing an update.
prepareSchema(action) {
const actionSchema = R.clone(schema)
switch (action) {
case 'insert':
actionSchema.$id = `/${schema.$id}-Insert`
actionSchema.required = Object.keys(schema.properties)
return actionSchema
default:
return schema
}
}
if you using the library jsonschema in python use custom validators:
first create custom validator:
# Custom validator for requiring all properties listed in the instance to be in the 'required' list of the instance
def allRequired(validator, allRequired, instance, schema):
if not validator.is_type(instance, "object"):
return
if allRequired and "required" in instance:
# requiring all properties to 'required'
instanceRequired = instance["required"]
instanceProperties = list(instance["properties"].keys())
for property in instanceProperties:
if property not in instanceRequired:
yield ValidationError("%r should be required but only the following are required: %r" % (property, instanceRequired))
for property in instanceRequired:
if property not in instanceProperties:
yield ValidationError("%r should be in properties but only the following are properties: %r" % (property, instanceProperties))
then extend an exsitsing validator:
all_validators = dict(Draft4Validator.VALIDATORS)
all_validators['allRequired'] = allRequired
customValidator = jsonschema.validators.extend(
validator=Draft4Validator,
validators=all_validators
)
now test:
schema = {"allRequired": True}
instance = {"properties": {"name": {"type": "string"}}, "required": []}
v = customValidator(schema)
errors = validateInstance(v, instance)
you will get the error:
'name' should be required but only the following are required: []
As suggested by others, here's such post-processing python code:
def schema_to_strict(schema):
if schema['type'] not in ['object', 'array']:
return schema
if schema['type'] == 'array':
schema['items'] = schema_to_strict(schema['items'])
return schema
for k, v in schema['properties'].items():
schema['properties'][k] = schema_to_strict(v)
schema['required'] = list(schema['properties'].keys())
schema['additionalProperties'] = False
return schema
You can use the function below:
export function addRequiredAttributeRecursive(schema) {
if (schema.type === 'object') {
schema.required = [];
Object.keys(schema.properties).forEach((key) => {
schema.required.push(key);
if (schema.properties[key].type === 'object') {
schema.properties[key] = addRequiredAttributeRecursive(
schema.properties[key],
);
} else if (schema.properties[key].type === 'array') {
schema.properties[key].items = addRequiredAttributeRecursive(
schema.properties[key].items,
);
}
});
} else if (schema.type === 'array') {
if (schema.items.type === 'object') {
schema.items = addRequiredAttributeRecursive(schema.items);
}
}
return schema;
}
It recursively write the required attribute for every property on all objects from the schema you have.
If you are using Javascript, you can use property getter.
{
"type": "object",
"properties": {
"elephant": {"type": "string"},
"giraffe": {"type": "string"},
"polarBear": {"type": "string"}
},
get required() { return Object.keys(this.properties) },
"additionalProperties": false
}
I recently ran into a problem when implementing the ajax functionality of jquery DataTables. Until I actually gave my json object collection an explicit name I couldn't get anything to display. Shouldn't there be a default data source if nothing named is returned?
Client Side control setup (includes hidden field that supplies data to dynamic anchor:
$('#accountRequestStatus').dataTable(
{
"destroy": true, // within a method that will be called multiple times with new/different data
"processing": true,
"ajax":
{
"type": "GET",
"url": "#Url.Action("SomeServerMethod", "SomeController")",
"data": { methodParam1: 12341, methodParam2: 123423, requestType: 4123421 }
}
, "paging": false
, "columns": [
{ "data": "DataElement1" },
{ "data": "DataElement2", "title": "Col1" },
{ "data": "DataElement3", "title": "Col2" },
{ "data": "DataElement4", "title": "Col3" },
{ "data": "DataElement5", "title": "Col4" },
]
, "columnDefs": [
{
"targets": 0, // hiding first column, userId
"visible": false,
"searchable": false,
"sortable": false
},
{
"targets": 5, // creates action link using the hidden data for that row in column [userId]
"render": function (data, type, row) {
return "<a href='#Url.Action("ServerMethod", "Controller")?someParam=" + row["DataElement1"] + "'>Details</a>"
},
"searchable": false,
"sortable": false
}
]
});
Here's a snippet of my server side code that returns the json collection.
tableRows is a collection of models containing the data to be displayed.
var json = this.Json(new { data = tableRows });
json.JsonRequestBehavior = JsonRequestBehavior.AllowGet;
return json;
As I said before, the ajax call returned data but wouldn't display until I gave the collection a name. Maybe I missed this required step in the documentation, but wouldn't it make sense for the control to wire up to a single returned collection as the default data source and not require the name? Figuring out the name thing equated to about 2+ hours of messin' around trying different things. That's all I'm saying.
Maybe this'll help someone else too...
dataTables does actually have a dataSrc property! dataTables will look for either a data or an aaData section in the JSON. Thats why you finally got it to work with new { data=tableRows }. That is, if dataSrc is not specified! If your JSON differs from that concept you must specify dataSrc :
If you return a not named array / collection [{...},{...}] :
ajax: {
url: "#Url.Action("SomeServerMethod", "SomeController")",
dataSrc: ""
}
If you return a JSON array named different from data or aaData, like customers :
ajax: {
url: "#Url.Action("SomeServerMethod", "SomeController")",
dataSrc: "customers"
}
If the content is nested like { a : { b : [{...},{...}] }}
ajax: {
url: "#Url.Action("SomeServerMethod", "SomeController")",
dataSrc: "a.b"
}
If you have really complex JSON or need to manipulate the JSON in any way, like cherry picking from the content - dataSrc can also be a function :
ajax: {
url: "#Url.Action("SomeServerMethod", "SomeController")",
dataSrc: function(json) {
//do what ever you want
//return an array containing JSON / object literals
}
}
Hope the above clears things up!
I am given the following JSON structure:
{
"document": {
"sections": {
"x": {
"title": "foo"
},
"y": {
"title": "bar"
}
}
}
}
How do I update value of the title property for a given section using the HTTP API?
I would like to provide a path (string) to get to the property.
This was fixed in build 2254. You should now be able to issue a single scripted patch like this:
EVAL http://localhost:8080/docs/foos/1
{Script:"this.document.sections.x.title = newTitle;",Values:{"newTitle":"Whatever"}}