U-SQL JsonTuple - How to access specific fields in JSON array - json

I'm extracting AVRO data which has a JSON field that I need to get values from. The JSON has an array, and I don't know what order the different elements of the array may appear in. How can I target specific node/values?
For example, Filters[0] could be Category one time, but could be AddressType another time.
I'm extracting AVRO data - i.e.
#rs =
EXTRACT date DateTime,
Body byte[]
FROM #input_file
USING new Microsoft.Analytics.Samples.Formats.ApacheAvro.AvroExtractor(#"
...
The Body is JSON that can look like this (but Category is not always Filter[0]. This is a small example; there are 7 different types of "Field"s):
{
""TimeStamp"": ""2019-02-19T15:00:29.1067771-05:00"",
""Filters"": [{
""Operator"": ""eq"",
""Field"": ""Category"",
""Value"": ""Sale""
}, {
""Operator"": ""eq"",
""Field"": ""AddressType"",
""Value"": ""Home""
}
]
}
My U-SQL looks like this, which of course does not always work.
#keyvalues =
SELECT JsonFunctions.JsonTuple(Encoding.UTF8.GetString(Body),
"TimeStamp",
"$.Filters[?(#.Field == 'Category')].Value",
"$.Filters[?(#.Field == 'AddressType')].Value"
) AS message
FROM #rs;
#results =
SELECT
message["TimeStamp"] AS TimeStamp,
message["Filters[0].Value"] AS Category,
message["Filters[1].Value"] AS AddressType
FROM #keyvalues;

Although this does not actually answer my question, as a workaround, I modified the Microsoft 'sample' JsonFunctions.JsonTuple method to be able to specify my own key name for extracted values:
/// Added - Prefix a path expression with a specified key. Use key~$e in the expression.
/// eg:
/// JsonTuple(json, "myId~id", "myName~name") -> field names MAP{ {myId, 1 }, {myName, Ed } }
The modified code:
private static IEnumerable<KeyValuePair<string, T>> ApplyPath<T>(JToken root, string path)
{
var keySeparatorPos = path.IndexOf("~");
string key = null;
var searchPath = path;
if (keySeparatorPos > 0) // =0?if just a leading "=", i.e. no key provided, then don't parse out a key.
{
key = path.Substring(0, keySeparatorPos).Trim();
searchPath = path.Substring(keySeparatorPos + 1);
}
// Children
var children = SelectChildren<T>(root, searchPath);
foreach (var token in children)
{
// Token => T
var value = (T)JsonFunctions.ConvertToken(token, typeof(T));
// Tuple(path, value)
yield return new KeyValuePair<string, T>(key ?? token.Path, value);
}
}
For example, I can access vales and name them
#keyvalues =
SELECT JsonFunctions.JsonTuple(Encoding.UTF8.GetString(Body),
"TimeStamp",
"EventName",
"Plan~ $.UrlParams.plan",
"Category~ $.Filters[?(#.Field == 'Category')].Value",
"AddressType~ $.Filters[?(#.Field == 'AddressType')].Value"
) AS message
FROM #rs;
#results =
SELECT
message["TimeStamp"] AS TimeStamp,
message["EventName"] AS EventName,
message["Plan"] AS Plan,
message["Category"] AS Category,
message["AddressType"] AS AddressType
FROM #keyvalues;
(I've not tested to see what would happen if the same Field appears multiple times in the array; That won't happen in my case)

Related

Multiple property filtering of data in array of object

I've a JSON object as below:
let data = [{"grade":"A","batch":"night", "rating":5}, {"grade":"B", "batch":"morning", "rating":6},
{"grade":"C", "batch":"night", "rating":7},
{"grade":"A", "batch":"morning", "rating":8}]
I want to filter json on two properties of object named "grade" and "batch"
How can I do this in javascript?
Here is sample code. you can add the filters object whichever data you want to filter and run the code. The result will be displayed in the console of the window.
You can try running the code snippet for output
function multiFilter(array, filters){
const filterKeys = Object.keys(filters);
// filters all elements passing the criteria
return array.filter((item) => {
// dynamically validate all filter criteria
return filterKeys.every(key => !!~filters[key].indexOf(item[key]));
});
}
let data = [{"grade":"A","batch":"night", "rating":5}, {"grade":"B", "batch":"morning", "rating":6},
{"grade":"C", "batch":"night", "rating":7},
{"grade":"A", "batch":"morning", "rating":8}]
let filters = {
"grade" : ["A", "B"],
"batch" : ["morning"]
};
let filtered = multiFilter(data, filters);
console.log(filtered);

JSON - look up values in array

With the following json
{
"Count":0,
"Message":{
"AppId":0
},
"Data":"[{\"application_name\": \"Grand Central\",\"feature_name\": \"1 Click Fix\",\"access_type_id\": 2,\"member_name\": \"GC_Remote_Support_Security\"},{\"application_name\": \"Grand Central\",\"feature_name\": \"Account Details\",\"access_type_id\": 2,\"member_name\": \"GC_Remote_Support_Security\"},{\"application_name\": \"Grand Central\",\"feature_name\": \"Account Summary\",\"access_type_id\": 2,\"member_name\": \"GC_Remote_Support_Security\"}]"
}
how do I go through the Data array, in the most succinct coding manner possible, to see if any feature_name matches a given string?
Since your JSON contains nested, quoted JSON, you will need nested deserializations using LINQ to JSON to parse your Data array. Having done so, you can use use SelectTokens to query with a JSONPath query to find nested properties named feature_name, then check their value:
var testString = "Account Summary";
var found = JToken.Parse(JObject.Parse(jsonString)["Data"].ToString()).SelectTokens("..feature_name").Any(t => (string)t == testString);
Debug.Assert(found == true); // No assert.
Update
If you want the all JObject with a "feature_name" property matching a given value, you can do:
var foundItems = JToken.Parse(JObject.Parse(jsonString)["Data"].ToString())
.SelectTokens("..feature_name")
.Where(t => (string)t == testString)
.Select(t => t.Ancestors().OfType<JObject>().First()) // Get the immediate parent JObject of the matching value
.ToList();

nodejs control json name

I've a function that gets 2 values name and value and now I'd like to turn them into a JSON, so for example lets say ive this function
function addin(name,val)
and then i'll call it
addin("age","28") -> this will return -> {age: 28}
addin("name","Roni") -> {name: Roni}
I've tried many things to find out how to make it done, Im getting many data so I tried this
var full_js = { };
_.forEach(data, function(val,name) {
full_js.name = val;
console.log(JSON.stringify(full_js));
});
again it can be any value and any name both of them are Random Strings.
but its not working, I get it as {"name": "Roni"} and {"name": "55"}.
thanks for the help.
use a different notation:
function addin(name, val) {
var full_js = {};
full_js[name] = val;
return JSON.stringify(full_js);
}
Ex:
at the moment you are always assigning the value to the name key, instead of the dynamic name key, keep in mind that the key will always be the string representation of the variable used.
for example, addin({}, 'rony'), will return {"[object Object]":"test"}

how to split a return text become individual string in extjs?

I want to split a returning text to become an individual string but i am noobie in extjs.Pls help me if any idea with it...thankz
my example code:
//my return "record" string is "1: 3-4-2011 to 9-4-2011"
Ext.getCmp('cboWeek').on('select', function(box, record, index)
{
DateFrom = new Date(record).format('m/d/Y');//split to 3-4-2011
DateTo = new Date(record).format('m/d/Y'); //split to 9-4-2011
Store.load({ params: {dateFrom : DateFrom, dateTo: DateTo }});
});
i think what you want is:
// if record is "1: 3-4-2011 to 9-4-2011"
var matches = record.match(/[0-9]+-[0-9]+-[0-9]+/g);
// matches[0] will be 3-4-2011 and matches[1] will be 9-4-2011
Store.load({ params: {dateFrom : matches[0], dateTo: matches[1] }});
</pre>
just a note: your dates are not what can be parsed using Date object neither using Ext.Date.parse, because month / day must be 2digits, if you manage to get 3-4-2011 to something like 03-04-2011 by doing "3-4-2011".replace(/([0-9]{1})[^0-9]+/g, '0$1-') you can get Date object using parse method of ext's date: Ext.Date.parse('03-04-2011', 'd-m-Y') then you can use format method on Date object

What is "compressed JSON"?

I see a lot of references to "compressed JSON" when it comes to different serialization formats. What exactly is it? Is it just gzipped JSON or something else?
Compressed JSON removes the key:value pair of json's encoding to store keys and values in seperate parallel arrays:
// uncompressed
JSON = {
data : [
{ field1 : 'data1', field2 : 'data2', field3 : 'data3' },
{ field1 : 'data4', field2 : 'data5', field3 : 'data6' },
.....
]
};
//compressed
JSON = {
data : [ 'data1','data2','data3','data4','data5','data6' ],
keys : [ 'field1', 'field2', 'field3' ]
};
This method of usage i found here
Content from link (http://www.nwhite.net/?p=242)
rarely find myself in a place where I am writing javascript applications that use AJAX in its pure form. I have long abandoned the ‘X’ and replaced it with ‘J’ (JSON). When working with Javascript, it just makes sense to return JSON. Smaller footprint, easier parsing and an easier structure are all advantages I have gained since using JSON.
In a recent project I found myself unhappy with the large size of my result sets. The data I was returning was tabular data, in the form of objects for each row. I was returning a result set of 50, with 19 fields each. What I realized is if I augment my result set I could get a form of compression.
// uncompressed
JSON = {
data : [
{ field1 : 'data1', field2 : 'data2', field3 : 'data3' },
{ field1 : 'data4', field2 : 'data5', field3 : 'data6' },
.....
]
};
//compressed
JSON = {
data : [ 'data1','data2','data3','data4','data5','data6' ],
keys : [ 'field1', 'field2', 'field3' ]
};
I merged all my values into a single array and store all my fields in a separate array. Returning a key value pair for each result cost me 8800 byte (8.6kb). Ripping the fields out and putting them in a separate array cost me 186 bytes. Total savings 8.4kb.
Now I have a much more compressed JSON file, but the structure is different and now harder to work with. So I implement a solution in Mootools to make the decompression transparent.
Request.JSON.extend({
options : {
inflate : []
}
});
Request.JSON.implement({
success : function(text){
this.response.json = JSON.decode(text, this.options.secure);
if(this.options.inflate.length){
this.options.inflate.each(function(rule){
var ret = ($defined(rule.store)) ? this.response.json[rule.store] : this.response.json[rule.data];
ret = this.expandData(this.response.json[rule.data], this.response.json[rule.keys]);
},this);
}
this.onSuccess(this.response.json, text);
},
expandData : function(data,keys){
var arr = [];
var len = data.length; var klen = keys.length;
var start = 0; var stop = klen;
while(stop < len){
arr.push( data.slice(start,stop).associate(keys) );
start = stop; stop += klen;
}
return arr;
}
});
Request.JSON now has an inflate option. You can inflate multiple segments of your JSON object if you so desire.
Usage:
new Request.JSON({
url : 'url',
inflate : [{ 'keys' : 'fields', 'data' : 'data' }]
onComplete : function(json){}
});
Pass as many inflate objects as you like to the option inflate array. It has an optional property called ’store’ If set the inflated data set will be stored in that key instead.
The ‘keys’ and ‘fields’ expect strings to match a location in the root of your JSON object.
Based in Paniyar's answer, we can convert a List of Objects in "compressed" Json format using C# like this:
var JsonString = serializer.Serialize(
new
{
cols = new[] { "field1", "field2", "field3"},
items = data.Select(x => new object[] {x.field1, x.field2, x.field3})
});
I used an array of object because the fields can be int, bool, string...
More Reduction:
If the field is repeated very often and it is a string type, you can get compressed a little be more if you add a distinct list of that field... for instance, a field name job position, city, etc are excellent candidate for this. You can add a distinct list of this items and in each item change the value for a reference number. That will make your Json more lite.
Compressed:
[["KeyA", "KeyB", "KeyC", "KeyD", "KeyE", "KeyF"],
["ValA1", "ValB1", "ValC1", "ValD1", "ValE1", "ValF1"],
["ValA2", "ValB2", "ValC2", "ValD2", "ValE2", "ValF2"],
["ValA3", "ValB3", "ValC3", "ValD3", "ValE3", "ValF3"],
["ValA4", "ValB4", "ValC4", "ValD4", "ValE4", "ValF4"]]
Uncompressed:
[{KeyA: "ValA1", KeyB: "ValB1", KeyC: "ValC1", KeyD: "ValD1", KeyE: "ValE1", KeyF: "ValF1"},
{KeyA: "ValA2", KeyB: "ValB2", KeyC: "ValC2", KeyD: "ValD2", KeyE: "ValE2", KeyF: "ValF2"},
{KeyA: "ValA3", KeyB: "ValB3", KeyC: "ValC3", KeyD: "ValD3", KeyE: "ValE3", KeyF: "ValF3"},
{KeyA: "ValA4", KeyB: "ValB4", KeyC: "ValC4", KeyD: "ValD4", KeyE: "ValE4", KeyF: "ValF4"}]
The most likely answer is that it really is just gzipped JSON. There is no other standard meaning to this phrase.
Re-organizing a homogenous array of JSON objects into a pair of arrays is a very useful technique to make the payload smaller and to speed up encoding and decoding, it is not commonly called "compressed JSON". I haven't run across it ever in open source or any open API, but we use this technique internally and call it "jsontable".