How to access individual values of a struct? - json

I'm trying to print the individual members of Results after parsing JSON data and assigning it to Question.
struct Question: Decodable
{
let response_code: Int
let results: [Results]
}
struct Results: Decodable
{
let category: String
let question: String
let correct_answer: String
let incorrect_answers: [String]
}
I tried using:
print(question.results)
But I get:
[Trivia_Game.Results(category: "Entertainment: Music", question: "Which of the following bands is Tom DeLonge not a part of?", correct_answer: "+44", incorrect_answers: ["Box Car Racer", "Blink-182", "Angels & Airwaves"])]
How do I access the individual members such as "category" or "question"?

You would have to first access an individual element of question.results, like so:
question.results[n] // where n represents a valid array index number
And then to access specific properties of that individual Results structure, you would do it in the same way as you would access the value of a property of any other struct. For example, if you wanted to get the value of the category member of a Results structure, you would do this:
question.results[n].category
And then if you wanted to print the value of that specific member (again, using the category member as an example), you would do this:
print(question.results[n].category)
Now, if you wanted to print out the value of the category member for each of the Results structures in the question.results array, then you could use a for loop like so:
for result in question.results {
print(result.category)
}
Hope that helps.

results is an array. You have to enumerate the array
let results = question.results
for result in results {
print(result.category, result.question)
}
or
question.results.forEach { print($0.category, $0.question) }

Related

How to use #CsvFileSource with records of arbitrary length

I want to achieve following - in a csv file there are records (lines) with comma-separated values of arbitrary length, then I want to pass to the parametrized test method first N (say, 3, but whatever) arguments a String, and the rest - as some collection. That said, I want to achieve something like this:
class Tests {
#DisplayName("Data Test")
#ParameterizedTest(name = "{0} → {1}; {2} → {3}")
#CsvFileSource(resources = ["/data.csv"], numLinesToSkip = 1)
fun runTests(spec0: String, spec1: String, input: String, outputs: List<String>) {
assertData(spec0, spec1, input, outputs)
}
}
However, I actually don't know what it the best way to do it. The current workaround I'm using is to just store dynamic length values as a single string with some separator and postprocess the last argument:
class Tests {
#DisplayName("Data Test")
#ParameterizedTest(name = "{0} → {1}; {2} → {3}")
#CsvFileSource(resources = ["/data.csv"], numLinesToSkip = 1)
fun runTests(spec0: String, spec1: String, input: String, outputs: String) {
assertData(spec0, spec1, input, outputs.split('␞'))
}
}
What would be the best (more idiomatic) way to achieve this?
I just don't want have data in csv file with this additional separator.

USql Call data in multidimensional JSON array

I have this JSON file in a data lake that looks like this:
{
"id":"398507",
"contenttype":"POST",
"posttype":"post",
"uri":"http://twitter.com/etc",
"title":null,
"profile":{
"#class":"PublisherV2_0",
"name":"Company",
"id":"2163171",
"profileIcon":"https://pbs.twimg.com/image",
"profileLocation":{
"#class":"DocumentLocation",
"locality":"Toronto",
"adminDistrict":"ON",
"countryRegion":"Canada",
"coordinates":{
"latitude":43.7217,
"longitude":-31.432},
"quadKey":"000000000000000"},
"displayName":"Name",
"externalId":"00000000000"},
"source":{
"name":"blogs",
"id":"18",
"param":"Twitter"},
"content":{
"text":"Description of post"},
"language":{
"name":"English",
"code":"en"},
"abstracttext":"More Text and links",
"score":{}
}
}
in order to call the data into my application, I have to turn the JSON into a string using this code:
DECLARE #input string = #"/MSEStream/{*}.json";
REFERENCE ASSEMBLY [Newtonsoft.Json];
REFERENCE ASSEMBLY [Microsoft.Analytics.Samples.Formats];
#allposts =
EXTRACT
jsonString string
FROM #input
USING Extractors.Text(delimiter:'\b', quoting:true);
#extractedrows = SELECT Microsoft.Analytics.Samples.Formats.Json.JsonFunctions.JsonTuple(jsonString) AS er FROM #allposts;
#result =
SELECT er["id"] AS postID,
er["contenttype"] AS contentType,
er["posttype"] AS postType,
er["uri"] AS uri,
er["title"] AS Title,
er["acquisitiondate"] AS acquisitionDate,
er["modificationdate"] AS modificationDate,
er["publicationdate"] AS publicationDate,
er["profile"] AS profile
FROM #extractedrows;
OUTPUT #result
TO "/ProcessedQueries/all_posts.csv"
USING Outputters.Csv();
This output the JSON into a .csv file that is readable and when I download the file all data is displayed properly. My problem is when I need to get the data inside profile. Because the JSON is now a string I can't seem to extract any of that data and put it into a variable to use. Is there any way to do this? or do I need to look into other options for reading the data?
You can use JsonTuple on the profile string to further extract the specific properties you want. An example of U-SQL code to process nested Json is provided in this link - https://github.com/Azure/usql/blob/master/Examples/JsonSample/JsonSample/NestedJsonParsing.usql.
You can use JsonTuple on the profile column to further extract specific nodes
E.g. use JsonTuple to get all the child nodes of the profile node and extract specific values like how you did in your code.
#childnodesofprofile =
SELECT
Microsoft.Analytics.Samples.Formats.Json.JsonFunctions.JsonTuple(profile) AS childnodes_map
FROM #result;
#values =
SELECT
childnodes_map["name"] AS name,
childnodes_map["id"] AS id
FROM #result;
Alternatively, if you are interested in specific values, you can also pass paramters to the JsonTuple function to get the specific nodes you want. The code below gets the locality node from the recursively nested nodes (as described by the "$..value" construct.
#locality =
SELECT Microsoft.Analytics.Samples.Formats.Json.JsonFunctions.JsonTuple(profile, "$..locality").Values AS locality
FROM #result;
Other supported constructs by JsonTuple
JsonTuple(json, "id", "name") // field names
JsonTuple(json, "$.address.zip") // nested fields
JsonTuple(json, "$..address") // recursive children
JsonTuple(json, "$[?(#.id > 1)].id") // path expression
JsonTuple(json) // all children
Hope this helps.

List json processing

I have difficulty processing a list a Scala:
Currently I have a list of like this
(List(JString(2437), JString(2445), JString(2428), JString(321)), CompactBuffer((4,1)))
and I would like after processing, the result will look like below:
( (2437, CompactBuffer((4,1))), (2445, CompactBuffer((4,1))), (2428, CompactBuffer((4,1))), (321, CompactBuffer((4,1))) )
Can any body help me with this issue?
Thank you very much.
Try this:
val pair = (List(JString(2437), JString(2445), JString(2428), JString(321)),
CompactBuffer((4,1)))
val result = pair._1.map((_, pair._2))
First, pair._1 gets the list from the tuple. Then, map performs the function on each element of the list. The function (_, pair._2) puts the given element from the list in a new tuple together with the second part of the pair tuple.

Meteor: how do I return data from fields in a specific object?

This should be a fairly simple one.
myobject has various properties, _id, name, createdBy, date etc
In my find query I want to only return specific fields from within myObject. So for example, what would I need to do to modify the find query below so that only name was returned?
myCollection.find({createdBy: someId}, {fields: {myObject: 1}}).fetch();
Currently this will return everything in myObject which it should do, I just want one field within myObject returned.
Here is a way to do it within the query:
myCollection.find({createdBy: someId}, {fields: {'myObject.name':
1}}).fetch();
Note the quotes around
'myObject.name'
Lets assume we are talking about posts, and a post document looks like this:
{
_id: 'abc123',
title: 'All about meteor',
author: {
firstName: 'David',
lastName: 'Weldon'
}
}
You can then extract all of the last names from all of the authors with this:
var lastNames = Posts.find().map(function(post) {
return post.author.lastName;
});
Modify the selector and options as needed for your collection. Using fields in this case may be a small optimization if you are running this on the server and fetching the data directly from the DB.

Groovy JsonBuilder not including collection

I have the following code:
def customers = Customer.findAll()
def json = new JsonBuilder()
json {
customers.each { customer ->
id customer.id
name customer.name
address customer.address
}
}
I'm expecting that the result is an json array of customers, but instead it only contains 1 customer. Note the customers list contains 2 elements.
I saw some other post mentioning to use something like:
customers.collect {
Customer c -> [id: c.id, name: c.name, address: c.address]
}
But this style does not really fit nicely in the builder. E.g. I have to use colons : to assign values.
Is there another approach without creating groovy objects?
What you need is just this.
def json = new JsonBuilder( customers )
if there are no additional item in customer that is not required in the json.
No, json is a map, and you need a list of maps. What you are doing with each is re-assigning the id, name and address fields, so you just get the last value.
So you need to collect a list of maps together as you have in the question.