How do I Decode this JSON in Swift 4 - json

I have this JSON response that i need decoded but i only need certain properties from it. I want to grab the Legend's name and the amount of kills they have on the legend. How do i struct by Legend Model in order to get the decoder to work properly?
`
"legends": {
"selected": {
"LegendName": "Pathfinder",
"data": [
{
"name": "Season 5 Kills",
"value": 757,
"key": "kills_season_5"
},
{
"name": "Kills",
"value": 1140,
"key": "kills"
}
],
"ImgAssets": {
"icon": "https:\/\/api.mozambiquehe.re\/assets\/icons\/pathfinder.png",
"banner": "https:\/\/api.mozambiquehe.re\/assets\/banners\/pathfinder.jpg"
}
},
"all": {
"Pathfinder": {
"data": [
{
"name": "Kills",
"value": 1140,
"key": "kills"
},
{
"name": "Damage",
"value": 257532,
"key": "damage"
},
{
"name": "Season 5 Kills",
"value": 757,
"key": "kills_season_5"
}
],
"ImgAssets": {
"icon": "https:\/\/api.mozambiquehe.re\/assets\/icons\/pathfinder.png",
"banner": "https:\/\/api.mozambiquehe.re\/assets\/banners\/pathfinder.jpg"
}
},
"Wraith": {
"data": [
{
"name": "Kills",
"value": 269,
"key": "kills"
},
{
"name": "Season 5 Wins",
"value": 7,
"key": "wins_season_5"
},
{
"name": "Season 5 Kills",
"value": 174,
"key": "kills_season_5"
}
],
"ImgAssets": {
"icon": "https:\/\/api.mozambiquehe.re\/assets\/icons\/wraith.png",
"banner": "https:\/\/api.mozambiquehe.re\/assets\/banners\/wraith.jpg"
}
},
"Octane": {
"data": [
{
"name": "Season 5 Kills",
"value": 106,
"key": "kills_season_5"
}
],
"ImgAssets": {
"icon": "https:\/\/api.mozambiquehe.re\/assets\/icons\/octane.png",
"banner": "https:\/\/api.mozambiquehe.re\/assets\/banners\/octane.jpg"
}
},
"Wattson": {
"ImgAssets": {
"icon": "https:\/\/api.mozambiquehe.re\/assets\/icons\/wattson.png",
"banner": "https:\/\/api.mozambiquehe.re\/assets\/banners\/wattson.jpg"
}
}
}
},
}
Above is the JSON response and i want the decoder to simply just display the legends and the kills and damage they have inside their data array. I am currently having trouble accessing the "Data" array under each legend.

You can use Codable to get the expected response. Use the below models,
struct Response: Codable {
let legends: Legends
}
struct Legends: Codable {
let all: [String:Legend]
}
struct Legend: Codable {
let data: [LegendData]?
var kills: Int {
return self.data?.filter({$0.key.lowercased() == "kills"}).first?.value ?? 0
}
var damage: Int {
return self.data?.filter({$0.key.lowercased() == "damage"}).first?.value ?? 0
}
}
struct LegendData: Codable {
let value: Int
let key: String
}
Since you only need the count of kills and damage for each Legend, there is no need to parse everything in the JSON.
In the Legend model, I've created 2 computed properties kills and damage. These properties will directly return the count of kills and damage for each legend without having to write that much code everytime you access it.
Now parse the JSON data like so,
do {
let response = try JSONDecoder().decode(Response.self, from: data)
response.legends.all.forEach { (name,legend) in
let kills = legend.kills
let damage = legend.damage
print("\(name) - Kills: \(kills), Damage: \(damage)")
}
} catch {
print(error)
}
Example Output:
Pathfinder - Kills: 1140, Damage: 257532
Octane - Kills: 0, Damage: 0
Wattson - Kills: 0, Damage: 0
Wraith - Kills: 269, Damage: 0

Related

Cannot convert value of type '[Surah]' to expected argument type 'Range<Int>'

hi Guys
i try to learn swift, i need your help
i try to connect json with swift i get errors
Cannot convert value of type '[Surah]' to expected argument type 'Range'
thank you vor the help
struct Surah: Codable {
struct Juz: Codable {
let index: String
let verse: Verse
}
struct Verse: Codable {
let start, end: String
}
enum Place: String, Codable {
case mecca = "Mecca"
case medina = "Medina"
}
enum TypeEnum: String, Codable {
case madaniyah = "Madaniyah"
case makkiyah = "Makkiyah"
}
let place: Place
let type: TypeEnum
let count: Int
let title, titleAr, index, pages: String
let juz: [Juz] }
/***************/
struct ContentView: View {
let surahs: [Surah] = Bundle.main.decode("source/surah.json")
var body: some View {
NavigationView{
List{
ForEach(surahs){section in
Section(header:Text(section.title)){
ForEach(section.juz, id: \.verse){juzs in
Text(juzs.verse.start)
}
}
}
}
}
}
}
JSON:
[{
"place": "Mecca",
"type": "Makkiyah",
"count": 7,
"title": "Al-Fatiha",
"titleAr":"الفاتحة",
"index": "001",
"pages": "1",
"juz": [
{
"index": "01",
"verse": {
"start": "verse_1",
"end": "verse_7"
}
}
]
},
{
"place": "Medina",
"type": "Madaniyah",
"count": 286,
"title": "Al-Baqara",
"titleAr":"البقرة",
"index": "002",
"pages": "2",
"juz": [
{
"index": "01",
"verse": {
"start": "verse_1",
"end": "verse_141"
}
},
{
"index": "02",
"verse": {
"start": "verse_142",
"end": "verse_252"
}
},
{
"index": "03",
"verse": {
"start": "verse_253",
"end": "verse_286"
}
}
]
}]
I'm trying to create forEach method for horizontal collection for properties
how can i call this part of json??
I hope someone can help me..
now i need to call second Json part in my Swift
{
"index": "001",
"name": "al-Fatihah",
"verse": {
"verse_1": "بِسْمِ ٱللَّهِ ٱلرَّحْمَٰنِ ٱلرَّحِيمِ",
"verse_2": "ٱلْحَمْدُ لِلَّهِ رَبِّ ٱلْعَٰلَمِينَ",
"verse_3": "ٱلرَّحْمَٰنِ ٱلرَّحِيمِ",
"verse_4": "مَٰلِكِ يَوْمِ ٱلدِّينِ",
"verse_5": "إِيَّاكَ نَعْبُدُ وَإِيَّاكَ نَسْتَعِينُ",
"verse_6": "ٱهْدِنَا ٱلصِّرَٰطَ ٱلْمُسْتَقِيمَ",
"verse_7": "صِرَٰطَ ٱلَّذِينَ أَنْعَمْتَ عَلَيْهِمْ غَيْرِ ٱلْمَغْضُوبِ عَلَيْهِمْ وَلَا ٱلضَّآلِّينَ"
},
"count": 7,
"juz": [
{
"index": "01",
"verse": {
"start": "verse_1",
"end": "verse_7"
}
}
]
}
how can I call it up and code it? or formatting
struct ContentView: View {
let surahs: [Surah] = Bundle.main.decode("source/surah.json")
var body: some View {
NavigationView{
List{
ForEach(surahs, id:\. index){section in
Section(header:Text(section.title)){
ForEach(section.juz, id: \.verse){juzs in
Text(juzs.verse.start)
}
}
}
}
}
}

How to create Struct for more then one json table in swift xcode

I am writing an IOS Application that need to read a JSON FIle.
I understood the best way to do that is to write a struct for that json file and parse the json into that struct to be able to use freely.
I have a Json file that is saved locally in one of the folders
{
"colors": [
{
"color": "black",
"category": "hue",
"type": "primary",
"code": {
"rgba": [255,255,255,1],
"hex": "#000"
}
},
{
"color": "white",
"category": "value",
"code": {
"rgba": [0,0,0,1],
"hex": "#FFF"
}
},
{
"color": "red",
"category": "hue",
"type": "primary",
"code": {
"rgba": [255,0,0,1],
"hex": "#FF0"
}
},
{
"color": "blue",
"category": "hue",
"type": "primary",
"code": {
"rgba": [0,0,255,1],
"hex": "#00F"
}
},
{
"color": "yellow",
"category": "hue",
"type": "primary",
"code": {
"rgba": [255,255,0,1],
"hex": "#FF0"
}
},
{
"color": "green",
"category": "hue",
"type": "secondary",
"code": {
"rgba": [0,255,0,1],
"hex": "#0F0"
}
},
],
"people": [
{
"first_name": "john",
"is_valid": true,
"friends_list": {
"friend_names": ["black", "hub", "good"],
"age": 13
}
},
{
"first_name": "michal",
"is_valid": true,
"friends_list": {
"friend_names": ["jessy", "lyn", "good"],
"age": 19
}
},
{
"first_name": "sandy",
"is_valid": false,
"friends_list": {
"friend_names": ["brown", "hub", "good"],
"age": 15
}
},
]
}
i created a struct for each one of the two tables:
import Foundation
struct Color {
var color: String
var category: String
var type: String
var code: [JsonCodeStruct]
}
struct Poeople {
var firsName: String
var is_valid: Bool
var friendsNames: [JsonFriendNames]
}
struct JsonFriendNames {
var friendNames: [String]
var age: String
}
struct JsonCodeStruct {
var rgba: [Double]
var hex: String
}
and I want to open the local json file
and assign it the structs that I gave and then read them easily in the code.
can you suggest me a way on how to do that?
First of all you need an umbrella struct to decode the colors and people keys
struct Root: Decodable {
let colors: [Color]
let people : [Person]
}
The types in your structs are partially wrong. The Color related structs are
struct Color: Decodable {
let color: String
let category: String
let type: String?
let code : ColorCode
}
struct ColorCode: Decodable {
let rgba : [UInt8]
let hex : String
}
and the Person related structs are
struct Person: Decodable {
let firstName : String
let isValid : Bool
let friendsList : Friends
}
struct Friends: Decodable {
let friendNames : [String]
let age : Int
}
Assuming you read the file with
let data = try Data(contentsOf: URL(fileURLWithPath:"/...."))
you can decode the JSON into the given structs with
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
do {
let result = try decoder.decode(Root.self, from: data)
print(result)
} catch { print(error) }

How to parse complex JSON in Swift 4 using Codable

I need help with parsing JSON from server. Here's the JSON:
{
"response": {
"items": [
{
"type": "post",
"source_id": -17507435,
"date": 1514538602,
"post_id": 4105,
"post_type": "post",
"text": "Some text here",
"marked_as_ads": 0,
"attachments": [
{
"type": "photo",
"photo": {
"id": 456239655,
"album_id": -7,
"owner_id": -17507435,
"user_id": 100,
"photo_75": "https://sun1-3.userapi.com/c840632/v840632924/3b7e7/4YUS7DlaLK8.jpg",
"photo_130": "https://sun1-3.userapi.com/c840632/v840632924/3b7e8/Ffpb4ZUlulI.jpg",
"photo_604": "https://sun1-3.userapi.com/c840632/v840632924/3b7e9/-pkl6Qdb9hk.jpg",
"width": 439,
"height": 312,
"text": "",
"date": 1514538602,
"post_id": 4105,
"access_key": "6a61a49570efd9c39c"
}
}
],
"post_source": {
"type": "api"
},
"comments": {
"count": 0,
"groups_can_post": true,
"can_post": 1
},
"likes": {
"count": 0,
"user_likes": 0,
"can_like": 1,
"can_publish": 1
},
"reposts": {
"count": 0,
"user_reposted": 0
},
"views": {
"count": 2
}
}
],
"profiles": [],
"groups": [
{
"id": 17507435,
"name": "Literature Museum",
"screen_name": "samlitmus",
"is_closed": 0,
"type": "group",
"is_admin": 0,
"is_member": 1,
"photo_50": "https://pp.userapi.com/c615722/v615722068/e58c/d5Y8E_5689s.jpg",
"photo_100": "https://pp.userapi.com/c615722/v615722068/e58b/Hm05ga3x2J8.jpg",
"photo_200": "https://pp.userapi.com/c615722/v615722068/e589/yoG_DDalFII.jpg"
},
{
"id": 27711883,
"name": "E:\\music\\melodic hardcore",
"screen_name": "e_melodic_hc",
"is_closed": 0,
"type": "page",
"is_admin": 0,
"is_member": 1,
"photo_50": "https://pp.userapi.com/c628220/v628220426/47092/xepNnC7pSBw.jpg",
"photo_100": "https://pp.userapi.com/c628220/v628220426/47091/uAokr-c3NQ8.jpg",
"photo_200": "https://pp.userapi.com/c628220/v628220426/4708f/eNY4vzooz4E.jpg"
},
{
"id": 81574241,
"name": "DOS4GW.EXE",
"screen_name": "dos4gw",
"is_closed": 0,
"type": "page",
"is_admin": 0,
"is_member": 1,
"photo_50": "https://pp.userapi.com/c622118/v622118651/e045/vlhV6QxtoLI.jpg",
"photo_100": "https://pp.userapi.com/c622118/v622118651/e044/P9mVUhXBV58.jpg",
"photo_200": "https://pp.userapi.com/c622118/v622118651/e043/Soq8oxCMB0I.jpg"
},
{
"id": 76709587,
"name": "Prosvet",
"screen_name": "prosvet_pub",
"is_closed": 0,
"type": "page",
"is_admin": 0,
"is_member": 0,
"photo_50": "https://pp.userapi.com/c630431/v630431500/b24a/GHox8AmDTXU.jpg",
"photo_100": "https://pp.userapi.com/c630431/v630431500/b249/H3mcC-K7htM.jpg",
"photo_200": "https://pp.userapi.com/c630431/v630431500/b248/9fyvB8gkcwc.jpg"
}
],
"next_from": "1/4105_1514494800_5"
}
}
What I need to get from this JSON are lines: "text", "comments", "likes", "reposts", "attachments".
Inside "attachments" field I want to get "photo_604" line.
Here's my code:
class NewsItems: Decodable {
var text: String?
var comments: Comments
var likes: Likes
var reposts: Reposts
var attachments: [Attachments]
}
class Comments: Decodable {
var count: Int?
}
class Likes: Decodable {
var count: Int?
}
class Reposts: Decodable {
var count: Int?
}
class Attachments: Decodable {
var attachments: AttachmentPhoto
}
class AttachmentPhoto: Decodable {
var photo: WhatIsInsideAttachmentsPhoto
}
class WhatIsInsideAttachmentsPhoto: Decodable {
var photo: String?
enum CodingKeys: String, CodingKey {
case photo = "photo_604"
}
}
class WhatIsIsideResponseNewsFeed: Decodable {
var items: [NewsItems]
}
public class ResponseNewsFeed: Decodable {
var response: WhatIsIsideResponseNewsFeed
}
But after making the request:
Alamofire.request(baseURL+methodName, parameters: parameters).responseData(completionHandler: { response in
if let result = response.result.value {
let decoder = JSONDecoder()
let myResponse = try! decoder.decode(ResponseNewsFeed.self, from: result)
completion(myResponse.response.items)
I get an error:
Fatal error: 'try!' expression unexpectedly raised an error:
Swift.DecodingError.keyNotFound(_UL_PetrovLeonid.NewsItems.(CodingKeys
in _FA9A2FC8130449AA328C19ACD9506C2D).attachments,
Swift.DecodingError.Context(codingPath:
[_UL_Leonid.ResponseNewsFeed.(CodingKeys in
_FA9A2FC8130449AA328C19ACD9506C2D).response, _UL_PetrovLeonid.WhatIsIsideResponseNewsFeed.(CodingKeys in _FA9A2FC8130449AA328C19ACD9506C2D).items, Foundation.(_JSONKey in _12768CA107A31EF2DCE034FD75B541C9)(stringValue: "Index 0", intValue: Optional(0))], debugDescription: "No value associated with key
attachments (\"attachments\").", underlyingError: nil))
Why is that happening and what do I need to do to solve it? I've been into coding only three months from now, so please forgive me beforehand if my problem seems silly.
Thank you.
The error message is very clear
... Swift.DecodingError.keyNotFound ... NewsItems.(CodingKeys in _FA9A2FC8130449AA328C19ACD9506C2D).attachments ... No value associated with key attachments (\"attachments\").
keyNotFound is key is missing
NewsItems.(CodingKeys ... ).attachments is the object for key attachments in NewsItems which is Attachments
No value associated with key attachments (\"attachments\") is what is says.
Shortly: There is no key attachments in Attachments which is true.
Look at your JSON
"attachments": [
{
"type": "photo",
"photo": {
The class equivalent is
class Attachments: Decodable {
let type : String
let photo : AttachmentPhoto
}
And AttachmentPhoto is supposed to be
class AttachmentPhoto: Decodable {
private enum CodingKeys : String, CodingKey {
case photo604 = "photo_604"
case id
}
let id : Int
let photo604 : String // or even URL
// etc.
}
Actually there is no need to use classes, in most cases a struct is sufficient.

Using JSON API Serializer to create more complicated JSON

The examples here don't go nearly far enough in explaining how to produce a more complicated structure...
If I want to end up with something like:
{
"data": {
"type": "mobile_screens",
"id": "1",
"attributes": {
"title": "Watch"
},
"relationships": {
"mobile_screen_components": {
"data": [
{
"id": "1_1",
"type": "mobile_screen_components"
},
{
"id": "1_2",
"type": "mobile_screen_components"
},
...
]
}
}
},
"included": [
{
"id": "1_1",
"type": "mobile_screen_components",
"attributes": {
"title": "Featured Playlist",
"display_type": "shelf"
},
"relationships": {
"playlist": {
"data": {
"id": "938973798001",
"type": "playlists"
}
}
}
},
{
"id": "938973798001",
"type": "playlists",
"relationships": {
"videos": {
"data": [
{
"id": "5536725488001",
"type": "videos"
},
{
"id": "5535943875001",
"type": "videos"
}
]
}
}
},
{
"id": "5536725488001",
"type": "videos",
"attributes": {
"duration": 78321,
"live_stream": false,
"thumbnail": {
"width": 1280,
"url":
"http://xxx.jpg?pubId=694940094001",
"height": 720
},
"last_published_date": "2017-08-09T18:26:04.899Z",
"streams": [
{
"url":
"http://xxx.m3u8",
"mime_type": "MP4"
}
],
"last_modified_date": "2017-08-09T18:26:27.621Z",
"description": "xxx",
"fn__media_tags": [
"weather",
"personality"
],
"created_date": "2017-08-09T18:23:16.830Z",
"title": "NOAA predicts most active hurricane season since 2010",
"fn__tve_authentication_required": false
}
},
...,
]
}
what is the most simple data structure and serializer I can set up?
I get stumped after something like:
const mobile_screen_components = responses.map((currentValue, index) => {
id[`id_${index}`];
});
const dataSet = {
id: 1,
title: 'Watch',
mobile_screen_components,
};
const ScreenSerializer = new JSONAPISerializer('mobile_screens', {
attributes: ['title', 'mobile_screen_components'],
mobile_screen_components: {
ref: 'id',
}
});
Which only gives me:
{
"data": {
"type": "mobile_screens",
"id": "1",
"attributes": { "title": "Watch" },
"relationships": {
"mobile-screen-components": {
"data": [
{ "type": "mobile_screen_components", "id": "1_0" },
{ "type": "mobile_screen_components", "id": "1_1" },
{ "type": "mobile_screen_components", "id": "1_2" },
{ "type": "mobile_screen_components", "id": "1_3" },
{ "type": "mobile_screen_components", "id": "1_4" },
{ "type": "mobile_screen_components", "id": "1_5" }
]
}
}
}
}
I have no idea how to get the "included" sibling to "data." etc.
So, the question is:
what is the most simple data structure and serializer I can set up?
Below is the simplest object that can be converted to JSON similar to JSON in the question using jsonapi-serializer:
let dataSet = {
id: '1',
title: 'Watch',
mobile_screen_components: [
{
id: '1_1',
title: 'Featured Playlists',
display_type: 'shelf',
playlists: {
id: 938973798001,
videos: [
{
id: 5536725488001,
duration: 78321,
live_stream: false
},
{
id: 5535943875001,
duration: 52621,
live_stream: true
}
]
}
}
]
};
To serialize this object to JSON API, I used the following code:
let json = new JSONAPISerializer('mobile_screen', {
attributes: ['id', 'title', 'mobile_screen_components'],
mobile_screen_components: {
ref: 'id',
attributes: ['id', 'title', 'display_type', 'playlists'],
playlists: {
ref: 'id',
attributes: ['id', 'videos'],
videos: {
ref: 'id',
attributes: ['id', 'duration', 'live_stream']
}
}
}
}).serialize(dataSet);
console.log(JSON.stringify(json, null, 2));
The first parameter of JSONAPISerializer constructor is the resource type.
The second parameter is the serialization options.
Each level of the options equals to the level of the nested object in serialized object.
ref - if present, it's considered as a relationships.
attributes - an array of attributes to show.
Introduction
First of all we have to understand the JSON API document data structure
[0.1] Refering to the top level (object root keys) :
A document MUST contain at least one of the following top-level
members:
data: the document’s “primary data”
errors: an array of error objects
meta: a meta object that contains non-standard meta-information.
A document MAY contain any of these top-level members:
jsonapi: an object describing the server’s implementation
links: a links object related to the primary data.
included: an array of resource objects that are related to the primary data and/or each other (“included resources”).
[0.2]
The document’s “primary data” is a representation of the resource or
collection of resources targeted by a request.
Primary data MUST be either:
a single resource identifier object, or
null, for requests that target single resources
an array of resource identifier
objects, or an empty array ([]), for reqs. that target
collections
Example
The following primary data is a single resource object:
{
"data": {
"type": "articles",
"id": "1",
"attributes": {
// ... this article's attributes
},
"relationships": {
// ... this article's relationships
}
}
}
In the (jsonapi-serializer) documentation : Available serialization option (opts argument)
So in order to add the included (top-level member) I performed the following test :
var JsonApiSerializer = require('jsonapi-serializer').Serializer;
const DATASET = {
id:23,title:'Lifestyle',slug:'lifestyle',
subcategories: [
{description:'Practices for becoming 31337.',id:1337,title:'Elite'},
{description:'Practices for health.',id:69,title:'Vitality'}
]
}
const TEMPLATE = {
topLevelLinks:{self:'http://example.com'},
dataLinks:{self:function(collection){return 'http://example.com/'+collection.id}},
attributes:['title','slug','subcategories'],
subcategories:{ref:'id',attributes:['id','title','description']}
}
let SERIALIZER = new JsonApiSerializer('pratices', DATASET, TEMPLATE)
console.log(SERIALIZER)
With the following output :
{ links: { self: 'http://example.com' },
included:
[ { type: 'subcategories', id: '1337', attributes: [Object] },
{ type: 'subcategories', id: '69', attributes: [Object] } ],
data:
{ type: 'pratices',
id: '23',
links: { self: 'http://example.com/23' },
attributes: { title: 'Lifestyle', slug: 'lifestyle' },
relationships: { subcategories: [Object] } } }
As you may observe, the included is correctly populated.
NOTE : If you need more help with your dataSet, edit your question with the original data.

How to access Dynamodb's original JSON elements?

I am trying to test my lambda manually with the following dynamodb event input configured in tests -
Let's call this Json-1
{
"Records": [
{
"eventID": "1",
"eventVersion": "1.0",
"dynamodb": {
"Keys": {
"Id": {
"N": "101"
}
},
"NewImage": {
"Message": {
"S": "New item!"
},
"Id": {
"N": "101"
}
},
"StreamViewType": "NEW_AND_OLD_IMAGES",
"SequenceNumber": "111",
"SizeBytes": 26
},
"awsRegion": "us-west-2",
"eventName": "INSERT",
"eventSourceARN": eventsourcearn,
"eventSource": "aws:dynamodb"
},
{
"eventID": "2",
"eventVersion": "1.0",
"dynamodb": {
"OldImage": {
"Message": {
"S": "New item!"
},
"Id": {
"N": "101"
}
},
"SequenceNumber": "222",
"Keys": {
"Id": {
"N": "101"
}
},
"SizeBytes": 59,
"NewImage": {
"Message": {
"S": "This item has changed"
},
"Id": {
"N": "101"
}
},
"StreamViewType": "NEW_AND_OLD_IMAGES"
},
"awsRegion": "us-west-2",
"eventName": "MODIFY",
"eventSourceARN": sourcearn,
"eventSource": "aws:dynamodb"
},
{
"eventID": "3",
"eventVersion": "1.0",
"dynamodb": {
"Keys": {
"Id": {
"N": "101"
}
},
"SizeBytes": 38,
"SequenceNumber": "333",
"OldImage": {
"Message": {
"S": "This item has changed"
},
"Id": {
"N": "101"
}
},
"StreamViewType": "NEW_AND_OLD_IMAGES"
},
"awsRegion": "us-west-2",
"eventName": "REMOVE",
"eventSourceARN": sourcearn,
"eventSource": "aws:dynamodb"
}
]
}
However, the json of dynamodb items look like this -
Let's call this Json-2
{
"id": {
"S": "RIGHT-aa465568-f4c8-4822-9c38-7563ae0cd37b-1131286033464633.jpg"
},
"lines": {
"L": [
{
"M": {
"points": {
"L": [
{
"L": [
{
"N": "0"
},
{
"N": "874.5625"
}
]
},
{
"L": [
{
"N": "1765.320601851852"
},
{
"N": "809.7800925925926"
}
]
},
{
"L": [
{
"N": "3264"
},
{
"N": "740.3703703703704"
}
]
}
]
},
"type": {
"S": "guard"
}
}
}
]
},
"modified": {
"N": "1483483932472"
},
"qastatus": {
"S": "reviewed"
}
}
Using the lambda function below, I can connect to my table. My goal is create a json which elastic search will accept.
#Override
public Object handleRequest(DynamodbEvent dynamodbEvent, Context context) {
List<DynamodbEvent.DynamodbStreamRecord> dynamodbStreamRecordlist = dynamodbEvent.getRecords();
DynamoDB dynamoDB = new DynamoDB(new AmazonDynamoDBClient());
log.info("Whole event - "+dynamodbEvent.toString());
dynamodbStreamRecordlist.stream().forEach(dynamodbStreamRecord -> {
if(dynamodbStreamRecord.getEventSource().equalsIgnoreCase("aws:dynamodb")){
log.info("one record - "+dynamodbStreamRecord.getDynamodb().toString());
log.info(" getting N from new image "+dynamodbStreamRecord.getDynamodb().getNewImage().toString());
String tableName = getTableNameFromARN(dynamodbStreamRecord.getEventSourceARN());
log.info("Table name :"+tableName);
Map<String, AttributeValue> keys = dynamodbStreamRecord.getDynamodb().getKeys();
log.info(keys.toString());
AttributeValue attributeValue = keys.get("Id");
log.info("Value of N: "+attributeValue.getN());
Table table = dynamoDB.getTable(tableName);
}
});
return dynamodbEvent;
}
The format of a JSON item that elastic search expects is this and this is what I want to map the test input json to-
Let's call this Json-3
{
_index: "bar-guard",
_type: "bar-guard_type",
_id: "LEFT-b1939610-442f-4d8d-9991-3ca54685b206-1147042497459511.jpg",
_score: 1,
_source: {
#SequenceNumber: "4901800000000019495704485",
#timestamp: "2017-01-04T02:24:20.560358",
lines: [{
points: [[0,
1222.7129629629628],
[2242.8252314814818,
1254.702546296296],
[4000.0000000000005,
1276.028935185185]],
type: "barr"
}],
modified: 1483483934697,
qastatus: "reviewed",
id: "LEFT-b1939610-442f-4d8d-9991-3ca54685b206-1147042497459511.jpg"
}
},
So what I need is read Json-1 and map it to Json-3.
However, Json-1 does not seem to be complete i.e. it does not have information that a dynamodb json has - like points and lines in Json-2.
And so, I was trying to get a connection to the original table and then read this additional information of lines and points by using the ID.
I am not sure if this is the right approach. Basically, want to figure out a way to get the actual JSON that dynamodb has and not the one that has attribute types
How can I get lines and points from json-2 using java? I know we have DocumentClient in javascript but I am looking for something in java.
Also, came across a converter here but doesn't help me- https://github.com/aws/aws-sdk-js/blob/master/lib/dynamodb/converter.js
Is this something that I should use DynamoDBMapper or ScanJavaDocumentAPI for ?
http://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/dynamodbv2/datamodeling/DynamoDBMapper.html#marshallIntoObjects-java.lang.Class-java.util.List-com.amazonaws.services.dynamodbv2.datamodeling.DynamoDBMapperConfig-
If yes, I am a little lost how to do that in the code below -
ScanRequest scanRequest = new ScanRequest().withTableName(tableName);
ScanResult result = dynamoDBClient.scan(scanRequest);
for(Map<String, AttributeValue> item : result.getItems()){
AttributeValue value = item.get("lines");
if(value != null){
List<AttributeValue> values = value.getL();
for(AttributeValue value2 : values){
//what next?
}
}
}
Ok, this seems to work for me.
ScanRequest scanRequest = new ScanRequest().withTableName(tableName);
ScanResult result = dynamoDBClient.scan(scanRequest);
for(Map<String, AttributeValue> item : result.getItems()){
AttributeValue value = item.get("lines");
if(value != null){
List<AttributeValue> values = value.getL();
for(AttributeValue value2 : values){
if(value2.getM() != null)
{
Map<String, AttributeValue> map = value2.getM();
AttributeValue points = map.get("points");
List<AttributeValue> pointsvalues = points.getL();
if(!pointsvalues.isEmpty()){
for(AttributeValue valueOfPoint : pointsvalues){
List<AttributeValue> pointList = valueOfPoint.getL();
for(AttributeValue valueOfPoint2 : pointList){
}
}
}
}
}
}
}