I am trying to drop elements from JSON. Here is my code:
String test = '[{
"type":"new",
"color":"red",
"items": ["aa","bb", "cc"]
}]';
var myJson = jsonDecode(test);
var result = myJson.where((a)=> a != 'items');
print(result);
It does not work. I need to drop items and get:
[{"type":"new","color":"red"}]
In the JSON, test array contains one object item with a property items. Thus, filtering is not caching it.
To remove items, you need to map over items and remove the items key from each.
UPDATED:
var result = myJson.map((a)=> {a.remove('items'); return a;} );
Related
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)
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);
When the first step return a json object like this
{
"success":true,
"total":21,
"items":
[
{"id":"762"},
{"id":"763"},
{"id":"764"}
]
}
how can i assign variable id to the first "id" item in response
i have done it like this but it didn't work
i also tried items.id, items[0].id but that didn't work either
To assign a variable to an item in a list, you can use a post-response script.
In this case, something like:
var data = JSON.parse(response.body);
var myId = data.items[0].id;
variables.set("id", myId);
I'm trying to use a PCRE regular expression to extract some JSON. I'm using a version of MariaDB which does not have JSON functions but does have REGEX functions.
My string is:
{"device_types":["smartphone"],"isps":["a","B"],"network_types":[],"countries":[],"category":["Jebb","Bush"],"carriers":[],"exclude_carriers":[]}
I want to grab the contents of category. I'd like a matching group that contains 2 items, Jebb and Bush (or however many items are in the array).
I've tried this pattern but it only matches the first occurrence: /(?<=category":\[).([^"]*).*?(?=\])/g
Does this match your needs? It should match the category array regardless of its size.
"category":(\[.*?\])
regex101 example
JSON not a regular language. Since it allows arbitrary embedding of balanced delimiters, it must be at least context-free.
For example, consider an array of arrays of arrays:
[ [ [ 1, 2], [2, 3] ] , [ [ 3, 4], [ 4, 5] ] ]
Clearly you couldn't parse that with true regular expressions.
See This Topic:
Regex for parsing single key: values out of JSON in Javascript
Maybe Helpful for you.
Using a set of non-capturing group you can extract a predefined json array
regex answer: (?:\"category\":)(?:\[)(.*)(?:\"\])
That expression extract "category":["Jebb","Bush"], so access the first group
to extract the array, sample java code:
Pattern pattern = Pattern.compile("(?:\"category\":)(?:\\[)(.*)(?:\"\\])");
String body = "{\"device_types\":[\"smartphone\"],\"isps\":[\"a\",\"B\"],\"network_types\":[],\"countries\":[],\"category\":[\"Jebb\",\"Bush\"],\"carriers\":[],\"exclude_carriers\":[]}";
Matcher matcher = pattern.matcher(body);
assertThat(matcher.find(), is(true));
String[] categories = matcher.group(1).replaceAll("\"","").split(",");
assertThat(categories.length, is(2));
assertThat(categories[0], is("Jebb"));
assertThat(categories[1], is("Bush"));
There are many ways. One sloppy way to do it is /([A-Z])\w+/g
Please try it on your console like
var data = '{"device_types":["smartphone"],"isps":["a","B"],"network_types":[],"countries":[],"category":["Jebb","Bush"],"carriers":[],"exclude_carriers":[]}',
res = [];
data.match(/([A-Z])\w+/g); // ["Jebb", "Bush"]
OK the above was pretty sloppy however a solid single regex solution to extract every single element regardless of the number, one by one and to place them in an array (res) is the following...
var rex = /[",]+(\w*)(?=[",\w]*"],"carriers)/g,
str = '{"device_types":["smartphone"],"isps":["a","B"],"network_types":[],"countries":[],"category":["Jebb","Bush","Donald","Trump"],"carriers":[],"exclude_carriers":[]}',
arr = [],
res = [];
while ((arr = rex.exec(str)) !== null) {
res.push(arr[1]); // <- ["Jebb", "Bush", "Donald", "Trump"]
}
Check it out # http://regexr.com/3d4ee
OK lets do it. I have come up with a devilish idea. If JS had look-behinds this could have been done simply by reversing the applied logic in the previous example where i had used a look-forward. Alas, there aren't... So i decided to turn the world the other way around. Check this out.
String.prototype.reverse = function(){
return this.split("").reverse().join("");
};
var rex = /[",]+(\w*)(?=[",\w]*"\[:"yrogetac)/g,
str = '{"device_types":["smartphone"],"isps":["a","B"],"network_types":[],"countries":[],"category":["Jebb","Bush","Donald","Trump"],"carriers":[],"exclude_carriers":[]}',
rev = str.reverse();
arr = [],
res = [];
while ((arr = rex.exec(rev)) !== null) {
res.push(arr[1].reverse()); // <- ["Trump", "Donald", "Bush", "Jebb"]
}
res.reverse(); // <- ["Jebb", "Bush", "Donald", "Trump"]
Just use your console to confirm.
In c++ you can do it like this
bool foundmatch = false;
try {
std::regex re("\"([a-zA-Z]+)\"*.:*.\\[[^\\]\r\n]+\\]");
foundmatch = std::regex_search(subject, re);
} catch (std::regex_error& e) {
// Syntax error in the regular expression
}
If the number of items in the array is limited (and manageable), you could define it with a finite number of optional items. Like this one with a maximum of 5 items:
"category":\["([^"]*)"(?:,"([^"]*)"(?:,"([^"]*)"(?:,"([^"]*)"(?:,"([^"]*)")?)?)?)?
regex101 example here.
Regards.
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();