Parsing JSON array in Swift 3 - arrays

I'm trying to parse JSON file to show in table view in Swift 3 without using external frameworks, but my knowledge in Swift is not enough. I have looked other questions, but nothing worked for me. The problem is that in my JSON there are couple of nested arrays.
Here is example of the JSON file:
"guides" : [
{
"name" : "First Guide",
"sections" : [
{
"title" : "Controls",
"data" : [
{
"value" : "controls.PNG",
"type" : "image"
},
{
"value" : "Sensitivity: Changes the sensitivity of the camera when turning.",
"type" : "text"
},
{
"value" : "Invert Y-Axis: Toggles inversion of camera when looking up/down.",
"type" : "text"
},
{
"value" : "crosshair.PNG",
"type" : "image"
},
{
"value" : "Lefty : Toggles the D-pad being on the left/right side of the screen.",
"type" : "text"
},
{
"value" : "Swap Jump and Sneak : Chooses whether to swap the position of jump and sneak buttons.",
"type" : "text"
},
{
"value" : "Button size - Changes the size of the buttons. Smaller buttons allow extra slots for the hotbar.",
"type" : "text"
}
]
},
{
"title" : "User Profile",
"data" : [
{
"value" : "profile.png",
"type" : "image"
},
{
"value" : "Use Cellular Data: Gives the Player the option to use cellular data.",
"type" : "text"
}
]
},
{
"title" : "Global Resources",
"data" : [
{
"value" : "resources.png",
"type" : "image"
},
..............
How I get parse the data into Swift arrays and use it to be displayed in UITableView controller. There are couple of "guides" in this JSON and I need to be able to show only one of them at the time.
Help will be much appreciated. Thank you in advance.

Try using following code:
let jsonString = "[\"a\",\"b\"]"
let jsonData = jsonString.data(using: .utf8)! as Data
do {
let dataJson = try JSONSerialization.jsonObject(with: jsonData, options: .mutableContainers)
print(dataJson)
}
catch {
print("error getting xml string: \(error)")
}

Related

Compare array within objects in an array of the same Mongo document

I have a Mongo database with multiple documents and they all contain 2 Items for in store and online locations. The difference will be that attributes within the items object may differ. I am trying to capture all documents that have differing attributes between the object items with the array.
I've tried using $expr and comparing the position of the elements such as "Items.0.Attributes" == "Items.1.Attributes" but had no luck.
{
"ID" : "123456789",
"Items" : [
{
"ItemDept" : "softLines",
"ProductId" : {
"Name" : "shirts",
"_id" : "12345Shirts"
},
"Attributes" : [ "blue","small","mens"],
"Season" : "Summer"
"Location":"online"
}
,
{
"ItemDept" : "softlines",
"ProductId" : {
"Name" : "shirts",
"_id" : "12345Shirts")
},
"Attributes" : [ "blue","small","women"],
"Season" : "Summer"
"Location":"stores"
}
]
}
If I understand what you want to find/output, here's one way you could do it.
db.collection.find({
"$expr": {
"$not": {
"$setEquals": [
{"$first": "$Items.Attributes"},
{"$last": "$Items.Attributes"}
]
}
}
})
Try it on mongoplayground.net.

How to add a field into an Elastic Search document with an array of objects value?

I am using Elastic Search 5.6 and I'd like to add a new field to an existing document. This field's value should be of type array. I was able to add a new field with an array of strings by sending a POST request with the following body
{"script" : "ctx._source.new_field = ['string1', 'string2']"}
to my endpoint
http://localhost:9200/my_index/my_mapping/item_173969/_update
and verified that the new field is there, but I need to set the value of this key to an array of objects instead. How can I do this? Specifically, I need my document to have:
"size": [
{
"item_size": "XL",
"country_size": "US"
}
]
You are almost there. I'm using ES 7.1 that ignores document type but the script part should work.
Ingesting data
PUT test_david/_doc/1
{
"name": "doc1"
}
Updating document
POST test_david/_update/1
{
"script": {
"source": "if (!ctx._source.containsKey('sizes')) ctx._source.sizes= new ArrayList(); ctx._source.sizes.add(params.data);",
"params": {
"data": {
"item_size": "XL",
"country_size": "US"
}
}
}
}
Note this will validate the document has the property sizes already created and add a new size to it.
Query
POST test_david/_search
Response
{
"took" : 1,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 1.0,
"hits" : [
{
"_index" : "test_david",
"_type" : "_doc",
"_id" : "1",
"_score" : 1.0,
"_source" : {
"name" : "doc1",
"sizes" : [
{
"country_size" : "US",
"item_size" : "XL"
}
]
}
}
]
}
}
About Nested Type
You use nested type only if you want to preserve the relationship between properties of the same children to make queries.
Object field type let to do searches like:
"item_size and/or item_country on any of the size objects"
Nested field type searches like:
"item_size and/or item_country on the same size object"
Not all nested fields needs to be of nested type. Only if you need to keep the relation between properties of the same children to do queries because nested type is more expensive and if you are only storing and displaying data it makes no sense to use this type of field.

How to use mongoose find to filter by inner arrays

{
"_id" : ObjectId("5fa27539e2b1a10d0fdb82ba"),
"extra_fields" : [
{
"tag" : "alias",
"value" : "thealias"
},
{
"tag" : "name",
"value" : "nobody"
},
]
}
This is the object I'm referring to, for example, I need to query all the objects which have a tag="alias" in the extra_fields array of each object. how can I achieve this with MongoDB? Any help would be highly appreciated.
UPDATE: Please check this,
{
"_id" : ObjectId("5fa1b8ee30caf0655a64104a"),
"status" : true,
"extra_fields" : [
{
"tag" : "alias",
"value" : "hes"
},
{
"linked_collection_id" : "5fa1946a3ef5864410728f1f",
"linked_master_id" : [
"5fa19884dae0ba587c891d9a"
]
},
{
"linked_collection_id" : "5f7d68861d5a43b422b12c6d",
"linked_master_id" : [
"5f7d6c3b629ab057b67fa789"
]
}
]
}
I need to know how can I retrieve objects which has linked_collection_id='abc' AND linked_master_id contains 'xyz'. Thanks
You only need "extra_fields.tag": "alias" to compare the field and the result.
The query is quite simple:
db.collection.find({
"extra_fields.tag": "alias"
})
In this way, every document with, at least, one 'tag' field with value 'alias' will be returned.
Example here
Edit:
To find by multiple fields you can use this:
db.collection.find({
"extra_fields.linked_collection_id": "abc",
"extra_fields.linked_master_id": "xyz"
})

mongodb - extract a particular value in an embedded array within an array

I'm fairly new to mongoDB, but I've managed to archive a load of documents into a new collection called documents_archived in the following format using an aggregation pipeleine:
{
"_id" : ObjectId("5a0046ef2039404645a42f52"),
"archive" : [
{
"_id" : ObjectId("54e60f49e4b097cc823afe8c"),
"_class" : "xxxxxxxxxxxxx",
"fields" : [
{
"key" : "Agreement Number",
"value" : "1002465507"
}
{
"key" : "Name",
"value" : "xxxxxxxx"
}
{
"key" : "Reg No",
"value" : "xxxxxxx"
}
{
"key" : "Surname",
"value" : "xxxxxxxx"
}
{
"key" : "Workflow Id",
"value" : "xxxxxxxx"
}
],
"fileName" : "Audit_C1002465507.txt",
"type" : "Workflow Audit",
"fileSize" : NumberLong(404),
"document" : BinData(0, "xxxxx"),
"creationDate" : ISODate("2009-09-25T00:00:00.000+0000"),
"lastModificationDate" : ISODate("2015-02-19T16:28:57.016+0000"),
"expiryDate" : ISODate("2018-09-25T00:00:00.000+0000")
}
]
}
Now, I'm trying to extract just the Agreement Number's value. However, I have tried many things that my limited knowledge, searching and documentation will allow. Wondered if the mongoDB experts out there can help. Thank you.
Here's a solution that uses the agg framework. I am assuming that each doc can have more than one entry in the archive field but only one Agreement Number in the fields array because your design appears to be key/value. If multiple Agreement Numbers show up in the fields array we'll have to add an additional $unwind but for the moment, this should work:
db.foo.aggregate([
{$unwind: "$archive"}
,{$project: {x: {$filter: {
input: "$archive.fields",
as: "z",
cond: {$eq: [ "$$z.key", "Agreement Number" ]}
}}
}}
,{$project: {_id:false, val: {$arrayElemAt: ["$x.value",0]} }}
]);
{ "val" : "1002465507" }
You can use following in mongo shell to extract only values:
db.documents_archived.find().forEach(function(doc) {
doc.archive[0].fields.forEach(function(field) {
if (field.key == "Agreement Number") {
print(field.value)
}
})
})

Logstash split xml into array

Is it possible to convert xml into array of objects using logstash?
That'd be my sample document:
{
"Title" : "My blog title",
"Body" : "My first post ever",
"Metadata" : "<root><Tags><TagTypeID>1</TagTypeID><TagValue>twitter</TagValue></Tags><Tags><TagTypeID>1</TagTypeID><TagValue>facebook</TagValue></Tags><Tags><TagTypeID>2</TagTypeID><TagValue>usa</TagValue></Tags><Tags><TagTypeID>3</TagTypeID><TagValue>smartphones</TagValue></Tags></root>"
}
Ideally, I'd like to output this:
{
"Title" : "My blog title",
"Body" : "My first post ever",
"Metadata" : [
{
"TagTypeID" : "1",
"TagValue" : "twitter"
},
{
"TagTypeID" : "1",
"TagValue" : "facebook"
},
{
"TagTypeID" : "2",
"TagValue" : "usa"
},
{
"TagTypeID" : "3",
"TagValue" : "smartphones"
}
]
}
However I'm not able to achieve that. I tried using xml filter like that:
xml
{
source => "Metadata"
target => "Parsed"
}
However, it outputs this
{
"Title" : "My blog title",
"Body" : "My first post ever",
"#version" : "1",
"#timestamp" : "2015-10-27T17:21:31.961Z",
"Parsed" : {
"Tags" : [
{
"TagTypeID" : ["1"],
"TagValue" : ["twitter"]
},
{
"TagTypeID" : ["1"],
"TagValue" : ["facebook"]
},
{
"TagTypeID" : ["2"],
"TagValue" : ["usa"]
},
{
"TagTypeID" : ["3"],
"TagValue" : ["smartphones"]
}
]
}
}
I don't want my values to be stored as arrays (I know there's always going to be just one value there).
I know what fields are going to be brought back from my input, so I can map structure myself and this doesn't need to be dynamic (although that would be nice).
Allow splitting of lists / arrays into multiple events seemed to be useful, but it's poorly documented and I couldn't find information how to use this filter for my use-case.
Logstash, split event from an xml file in multiples documents keeping information from root tags is similar, but not exactly what I'd like to achieve.
Logstash: XML to JSON output from array to string this seems to be useful, however it hardcodes that first element of array must be outputed as single item (not part of array). It brings me back this:
{
"Title" : "My blog title",
"Body" : "My first post ever",
"#version" : "1",
"#timestamp" : "2015-10-27T17:21:31.961Z",
"Parsed" : {
"Tags" : [
{
"TagTypeID" : "1",
"TagValue" : "twitter"
},
{
"TagTypeID" : ["1"],
"TagValue" : ["facebook"]
},
{
"TagTypeID" : ["2"],
"TagValue" : ["usa"]
},
{
"TagTypeID" : ["3"],
"TagValue" : ["smartphones"]
}
]
}
}
Can this be done without having to create custom filters? (I've no
experience in Ruby)
Or am I missing something basic here?
Here is one approach using logstash's builtin ruby filter.
Filter section:
filter {
xml {
source => "Metadata"
target => "Parsed"
}
ruby { code => "
event['Parsed']['Tags'].each do |x|
x.each do |key, value|
x[key] = value[0]
end
end"
}
}
Output:
"Parsed":{
"Tags":[
{
"TagTypeID":"1",
"TagValue":"twitter"
},
{
"TagTypeID":"1",
"TagValue":"facebook"
},
{
"TagTypeID":"2",
"TagValue":"usa"
},
{
"TagTypeID":"3",
"TagValue":"smartphones"
}
]
}
If I understand you correctly this is your desired result. You need to specify the xml field inside the ruby filter: event['Parsed']['Tags']. Does it need to be more dynamic? Let me know if you need anything else.
Can this be done without having to create custom filters? (I've no experience in Ruby)
Well, yes and no. Yes, because this is not really a custom filter but a built-in solution. No, because I tend to say this can not be done without Ruby. I must admit that Ruby seems to be an unattractive solution. However, this is a flexible approach and 5 lines of code shouldn't hurt that much.
Most recent Logstash version (5.1.1 at this point) has updated XML filter, which has force_array option. It is enabled by default. Setting this to false will do exactly the same thing as ruby filter in accepted answer.
Taken from documentation:
force_contentedit
Value type is boolean
Default value is false
By default the filter will expand attributes differently from content inside of tags. This option allows you to force text content and attributes to always parse to a hash value.
https://www.elastic.co/guide/en/logstash/current/plugins-filters-xml.html#plugins-filters-xml-force_array

Resources