How to retrieve JSON key having array of values using YAJL RPGLE - rpgle

I am just starting to explore on writing/parsing JSON using YAJL in RPGLE
I am encountering a situation were i need to parse a key with array of values
e.g. {"key":[value1,value2,value2]}
I am seeing examples to parse array of objects i.e. { "key" : [ {"k1":"v1"}, {"k2":"v2"} , {"k3":"v3"} ] }
list = YAJL_object_find(docNode: 'key');
i = 0;
dow YAJL_ARRAY_LOOP( list: i: node );
val = YAJL_object_find(node: 'k1');
value1 = yajl_get_string(val);
enddo;
But not for the array of values for single Key. Any idea how we can do this using YAJL in RPGLE.
Thanks in Advance..!!

This is simply a matter of removing a line in your example and making a small modification. You have no need to look for the object in the array loop because you already have the relevant value.
list = YAJL_object_find(docNode: 'key');
i = 0;
dow YAJL_ARRAY_LOOP( list: i: node );
value1 = yajl_get_string(node);
enddo;
If you are on the latest version of IBM i (7.3 TR4 as of this comment), you should probably look into using the DATA-INTO RPG opcode or if you want it in a relational format, you can use SQL JSON_TABLE.

Related

How to extract raw values for comparison or manipulation from Gremlin (Tinkerpop)

I know I'm missing something obvious here. I'm trying to extract values from TitanDB using Gremlin in order to compare them within Groovy.
graph = TinkerFactory.createModern()
g = graph.traversal(standard())
markoCount = g.V().has('name','marko').outE('knows').count()
lopCount = g.V().has('name','lop').outE('knows').count()
if(markoCount > lopCount){
// Do something
}
But apparently what I'm actually (incorrectly) doing here is comparing traversal steps which obviously won't work:
Cannot compare org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.DefaultGraphTraversal with value '[TinkerGraphStep(vertex,[name.eq(marko)]), VertexStep(OUT,[knows],edge), CountGlobalStep]' and org.apache.tinkerpop.gremlin.process.traversal.dsl.graph.DefaultGraphTraversal with value '[TinkerGraphStep(vertex,[name.eq(lop)]), VertexStep(OUT,[knows],edge), CountGlobalStep]'
I'm having the same issue extracting values from properties for use in Groovy as well. I didn't see anything in the docs indicating how to set raw values like this.
What is needed to return actual values from Gremlin that I can use later in my Groovy code?
Figured it out, I needed next():
graph = TinkerFactory.createModern()
g = graph.traversal(standard())
markoCount = g.V().has('name','marko').outE('knows').count().next()
lopCount = g.V().has('name','lop').outE('knows').count().next()
if(markoCount > lopCount){
// Do something
}

what is the use of the keyMirror node package part of facebook's library?

This is the keyMirror package found here
https://www.npmjs.com/package/keymirror
it defines it as A simple utility for creating an object with values equal to its keys
Input: {key1: val1, key2: val2}
Output: {key1: key1, key2: key2}
But why would i need to do this?
how is this different from say,
{OPTION_ONE:1, OPTION_TWO:2, OPTION_THREE:3}
Why would an application find the below transformation to the above input useful?
{OPTION_ONE:OPTION_ONE, OPTION_TWO:OPTION_TWO, OPTION_THREE:OPTION_THREE}
It's making an Enum object (https://en.wikipedia.org/wiki/Enumerated_type)
You could do, like you said {OPTION_ONE:1, OPTION_TWO:2, OPTION_THREE:3}, which is a similar Enum object, but what if you wanted to know if the value 6 was a value from the enum? You would have to loop over all the keys and check all the values.
But, if the keys and values match, then you can just check if the key exists in the object to know if the value also does.
var mirror = keyMirror({a: null, b:null});
var someValue = 'd';
var validValue = mirror[someValue] !== undefined;

take multiple array fields as parameter

I am trying to refactor some code. All along the code base, I have code that stores user-related informations like this :
this.users[user][field] = data ;
Note that there could be an arbitrary number of subfields (including none), like this:
this.users[user][field][subfield1][subfield2] = data ;
Theses informations are retrieved like this :
var result = this.users[user][field] ;
In production, the actual data will be stored into Redis.
To prepare for this, I would like to refactor those access into two functions, say function storeUserData(user, fields, data) and function retrieveUserData(user, field).
I can do it trivially if there is only one field. But how can I write those two functions to allow for an arbitrary number of subfields (ideally none as well) ?
Edit : the long-term goal is to blur the difference between redis keys and node.js arrays.
That way I could for instance access a node subfield like this : 'users.user.id' and also have it in redis like this :users.user.*.id. Does that seem feasible ?
You can pass the fields argument as an Array. Then in your read function do something like
function retrieveUserData(user, fields) {
// imagine fields is ['field', 'subfield1']
var fieldVariable = this.users[user]
for (f = 0; f < fields.length; ++f) {
fieldVariable = fieldVariable[fields[f]];
}
// in this line fieldVariable will point to this.users[user]['field']['subfield1']
return fieldVariable;
}
Hope it helps!

Can I convert a JSON string to a Flex ArrayCollection in without changing the item order?

Regarding this issue, I have generated dynamically string from Java .each time string format change , for example String format is
[{"BranchName":"Corporate Office","Date":"08\/03\/2013","SPName":"Pharmacy","SPAmount_5-00%":"100.00","SPVATAmount_5-00%":"15.00","SPOtherCharges_5-00%":"30.00","SPAmount_14-50%":"200.00","SPVATAmount_14-50%":"39.00","SPOtherCharges_14-50%":"71.00","SPColTPA":"100.00","SPColChequeDD":"50.00","SPHdfcCC":"100.00","SPIdbiCC":"100.00","SPColCash":"50.00","Difference":"55.00"},
But when I convert array collection with following code .
var rawData:String = String(event.result);
var arr:Array = (JSON.decode(rawData) as Array);
var dp:ArrayCollection = new ArrayCollection(arr);
but array collection order changed as default sort like [Branch, Date, Difference,.. ] . But I want same as string format order. So How can I prevent Default order.
Actually, what you've described here is an array of objects (your example just includes one object). In the JSON parsing to array, each object is indeed in the order in which it is declared; but in the OBJECTS that are created, the properties may not be listed in the same order.
For example:
'[ {"Branch":"Corporate", "Department":"Finance", "Cost":"10000", "Attended":"true"},' +
'{"Branch":"Las Vegas", "Department":"Hospitality", "Cost":"20100", "Attended":"false"},' +
'{"Branch":"San Diego", "Department":"Banking", "Cost":"11023", "Attended":"true"}]'
Parsing would return arr[0] as the Corporate object, arr[1] as the Las Vegas object, etc. Iterating through the properties I got:
var obj:Object = dp.getItemAt(0);
for (var prop:String in obj) {
trace(prop + ' is ' + obj[prop]);
}
Department is Finance
Attended is true
Branch is Corporate
Cost is 10000

What is wrong in this LINQ Query, getting compile error

I have a list AllIDs:
List<IAddress> AllIDs = new List<IAddress>();
I want to do substring operation on a member field AddressId based on a character "_".
I am using below LINQ query but getting compilation error:
AllIDs= AllIDs.Where(s => s.AddressId.Length >= s.AddressId.IndexOf("_"))
.Select(s => s.AddressId.Substring(s.AddressId.IndexOf("_")))
.ToList();
Error:
Cannot implicitly convert type 'System.Collections.Generic.List<string>' to 'System.Collections.Generic.List<MyCompany.Common.Users.IAddress>'
AllIDs is a list of IAddress but you are selecting a string. The compiler is complaining it cannot convert a List<string> to a List<IAddress>. Did you mean the following instead?
var substrings = AllIDs.Where(...).Select(...).ToList();
If you want to put them back into Address objects (assuming you have an Address class in addition to your IAddress interface), you can do something like this (assuming the constructor for Address is in place):
AllIDs = AllIDs.Where(...).Select(new Address(s.AddressID.Substring(s.AddressID.IndexOf("_")))).ToList();
You should also look at using query syntax for LINQ instead of method syntax, it can clean up and improve the readability of a lot of queries like this. Your original (unmodified) query is roughly equivalent to this:
var substrings = from a in AllIDs
let id = a.AddressId
let idx = id.IndexOf("_")
where id.Length >= idx
select id.Substring(idx);
Though this is really just a style thing, and this compiles to the same thing as the original. One slight difference is that you only have to call String.IndexOf() one per entry, instead of twice per entry. let is your friend.
Maybe this?
var boundable =
from s id in AllIDs
where s.AddressId.Length >= s.AddressId.IndexOf("_")
select new { AddressId = s.AddressId.Substring(s.AddressId.IndexOf("_")) };
boundable = boundable.ToList();

Resources