JSON data divided by using segmented control - ios

I have some JSON data. The data is like below and I took a segmented control which contains active state and pending state, by using segmented control separate the JSON data. If order_status = 0 (below JSON data) that will store in pending state, if order_status = 1 that will store in active state.
I know how to parse JSON but I do not know how to separate the data by using segmented control.
{
"status": "done",
"order_data": [{
"price": "1000",
"qty": "1",
"total_price": "1000",
"voucher_id": "NIL",
"purchase_id": "1005",
"purchase_on": "NIL",
"validity": "30 days from the date of purchase",
"left_day": "NIL",
"order_status": 0
}, {
"price": "3000",
"qty": "1",
"total_price": "3000",
"voucher_id": "NIL",
"purchase_id": "10070",
"purchase_on": "NIL",
"validity": "30 days from the date of purchase",
"left_day": "NIL",
"order_status": 1
}, {
"price": "3000",
"qty": "1",
"total_price": "3000",
"voucher_id": "NIL",
"purchase_id": "1076767",
"purchase_on": "NIL",
"validity": "30 days from the date of purchase",
"left_day": "NIL",
"order_status": 1
}]
}

Let suppose that your data is in a variable named as jsonData, then firstly parse the json data and get two array of dictionary, one for pending state data and another one for active state data, then use both of the dictionary for segment control.
if let orderData = jsonData["order_data"] as? [[String:Any]] {
let pendingStateData = orderData.filter({ (newOrder) -> Bool in
return (newOrder["order_status"] as? Int) == 0
})
let activeStateData = orderData.filter({ (newOrder) -> Bool in
return (newOrder["order_status"] as? Int) == 1
})
}
So, using these filter you can filter the data and can get the desired filter data according to you.

Related

Swift Firebase Database: How to filter values by child key

I don't understand how to filter the data lists
my db has the following form
{
"numbers": [0, 1, 2, 3, 4, 5],
"models": {
"random_string_key": {
"name": "model_name",
"value": "some_value"
},
"random_string_key-2": {
"name": "Name",
"value": "any value"
}
}
}
How i can get array from numbers where all values < 3?
How i can filter models and get array models where value == "some_value"?
I would like to understand what I am doing wrong
let ref = Database.database().reference()
let refNumbers = ref.child("numbers")
refNumbers
.getData(completion: { error, snapshot in
// snapshot.value == [0, 1, 2, 3, 4, 5]
// OK
})
refNumbers
.queryOrderedByValue()
.queryEnding(beforeValue: 2)
.getData(completion: { error, snapshot in
/*
error: Unable to get latest value for query FQuerySpec (path: /numbers, params: {
en = "[MIN_NAME]";
ep = 2;
i = ".value";
}), client offline with no active listeners and no matching disk cache entries
why???
*/
})
let modelsRef = ref.child("models")
modelsRef
.getData(completion: { error, snapshot in
// snapshot.value == NSDictionary
// OK
/*
[
"key": String
"value": NSDictionary
]
*/
})
modelsRef
.queryEqual(toValue: "some_value", childKey: "value")
.getData(completion: { error, snapshot in
/*
error: null
snapshot.value == nil
why???
*/
})
modelsRef
.queryOrdered(byChild: "value")
.queryEqual(toValue: "some_value")
.getData(completion: { error, snapshot in
/*
Unable to get latest value for query FQuerySpec (path: /models, params: {
ep = some_value;
i = value;
sp = some_value;
}), client offline with no active listeners and no matching disk cache entries
why???
*/
})
I tried all the options that I found on the Internet but the result is 0
Either I get all the data from the list and filter it in the app, or I get nothing
Is it possible to filter the data upon receipt?
It is a bit difficult to give you a solution to the issues you described above but I can tell you where you're going wrong.
For #1, when you do the below
...
refNumbers
.queryOrderedByValue()
.queryEnding(beforeValue: 2)
.getData(completion: { error, snapshot in
...
})
refNumbers is not an array of numbers, it is an 'object'. And queryOrderedByValue() will not work on this 'single object', neither will .queryEnding(beforeValue: 2). You either need to do what you're doing, which is to get the entire data, convert to swift native types and filter, or you need to restructure your data on the DB side.
Similarly, in-case of #2, the object modelsRef is composed of a number of objects with random keys. So, when you perform a .queryEqual(toValue: "some_value", childKey: "value") operation, it will not find the child-key named 'value'. This child key is actually a child-key for the objects that modelsRef is composed of.
So, again, either you need to get all this data, type cast to native swift types and then filter, or somehow restructure your data.
So, the answer to your question is essentially either continue what you're doing (get data to the app and filter using native swift API which may present scalability challenges later depending on the amount of data), or, restructure your data.
Example with queryStarting & queryEnding
As requested, here is what works for me.
Database design
I have an event based app, using Firebase Realtime Database, with one parent node, lets call it events for now, because the real example is mainly in German.
Under events there is one child for each event, obviously:
{
"events": {
"-L_nMRK8mzXal47IE54x": {
"endDate": 1568715118,
"lat": 48.4382387,
"lon": 10.0499972044298,
"name": "Exampletown - event",
"city": "Exampletown",
"zip": "12345",
"startDate": 1568325600,
"street": "Street 11"
},
"-L_nMRK8mzXal47IE54y": {
"endDate": 1568715118,
"lat": 49.4382387,
"lon": 10.0499972044298,
"name": "Exampletown - event 2",
"city": "Exampletown",
"zip": "12345",
"startDate": 1568325600,
"street": "Street 12"
},
}
}
Swift 4.2
Inside a method I use the following to query the database for all past events based on the current timestamp:
let ref = Database.database().reference()
let query = ref.child("events").queryOrdered(byChild: "endDate").queryStarting(atValue: diffInterval, childKey: "endDate").queryEnding(atValue: now, childKey: "endDate")
// observe single event is sufficient for my app
query.observeSingleEvent(of: .value) { (snapshot) in
if snapshot.childrenCount > 0 {
for snap in snapshot.children {
// create an object for each of the objects of the snapshot
guard let eventData = self.getEventsFromSnapshot(snap: snap as! DataSnapshot) else {return}
// do something with eventData
}
} else {
// custom logging and return of empty array
}
}

Sort through JSON to find each instance that a string is different

I am attempting to find each instance of the string name: being different.
As for the example of JSON below I want to pull Alamo Draft House Lamar and Alamo Draft House Ritz and place them into an array.
JSON:
[{
"tmsId": "MV011110340000",
"rootId": "15444050",
"subType": "Feature Film",
"title": "Bohemian Rhapsody",
"releaseYear": 2018,
"releaseDate": "2018-11-02",
"titleLang": "en",
"descriptionLang": "en",
"entityType": "Movie",
"genres": ["Biography", "Historical drama", "Music"],
"longDescription": "Singer Freddie Mercury, guitarist Brian May, drummer Roger Taylor and bass guitarist John Deacon take the music world by storm when they form the rock 'n' roll band Queen in 1970. Surrounded by darker influences, Mercury decides to leave Queen years later to pursue a solo career. Diagnosed with AIDS in the 1980s, the flamboyant frontman reunites with the group for Live Aid -- leading the band in one of the greatest performances in rock history.",
"shortDescription": "Singer Freddie Mercury of Queen battles personal demons after taking the music world by storm.",
"topCast": ["Rami Malek", "Lucy Boynton", "Gwilym Lee"],
"directors": ["Bryan Singer"],
"officialUrl": "https://www.foxmovies.com/movies/bohemian-rhapsody",
"ratings": [{
"body": "Motion Picture Association of America",
"code": "PG-13"
}],
"advisories": ["Adult Language", "Adult Situations"],
"runTime": "PT02H15M",
"preferredImage": {
"width": "240",
"height": "360",
"uri": "assets/p15444050_v_v5_as.jpg",
"category": "VOD Art",
"text": "yes",
"primary": "true"
},
"showtimes": [{
{
"theatre": {
"id": "9489",
"name": "Alamo Drafthouse at the Ritz"
},
"dateTime": "2018-11-10T19:15",
"barg": false,
"ticketURI": "http://www.fandango.com/tms.asp?t=AAUQP&m=185586&d=2018-11-10"
}, {
"theatre": {
"id": "9489",
"name": "Alamo Drafthouse at the Ritz"
},
"dateTime": "2018-11-10T22:30",
"barg": false,
"ticketURI": "http://www.fandango.com/tms.asp?t=AAUQP&m=185586&d=2018-11-10"
}, {
"theatre": {
"id": "5084",
"name": "Alamo Drafthouse South Lamar"
},
"dateTime": "2018-11-10T12:00",
"barg": false,
"ticketURI": "http://www.fandango.com/tms.asp?t=AATHS&m=185586&d=2018-11-10"
}, {
"theatre": {
"id": "5084",
"name": "Alamo Drafthouse South Lamar"
},
"dateTime": "2018-11-10T15:40",
"barg": false,
"ticketURI": "http://www.fandango.com/tms.asp?t=AATHS&m=185586&d=2018-11-10"
},
}]
}]
Here is my api code:
var shows = [Shows]()
struct Shows: Codable {
let showtimes: [Showtimes]
struct Showtimes: Codable {
let theatre: Theater
struct Theater: Codable {
let id: String
let name: String
}
}
}
func loadShowtimes() {
let apiKey = ""
let today = "2018-11-10"
let zip = "78701"
let filmId = "MV011110340000"
let radius = "15"
let url = URL(string: "http://data.tmsapi.com/v1.1/movies/\(filmId)/showings?startDate=\(today)&numDays=5&zip=\(zip)&radius=\(radius)&api_key=\(apiKey)")
let request = URLRequest(
url: url! as URL,
cachePolicy: URLRequest.CachePolicy.reloadIgnoringLocalCacheData,
timeoutInterval: 10 )
let session = URLSession (
configuration: URLSessionConfiguration.default,
delegate: nil,
delegateQueue: OperationQueue.main
)
let task = session.dataTask(with: request, completionHandler: { (data, response, error) in
if let data = data {
do { let shows = try! JSONDecoder().decode([Shows].self, from: data)
self.shows = shows
}
}
})
task.resume()
}
How would I approach sorting through the array and finding each instance of name: being different, then take each name and place them into a new array?
There are several ways to iterate through your array of Shows and their array of Theater to get the complete list of names. Once you have the full list of names you can get a unique list of those names.
Here is one approach:
let names = Array(Set(shows.map { $0.showtimes.map { $0.theatre.name }}.reduce([]) { $0 + $1 }))
Let's split that up to better explain what is going on.
let allNames = shows.map { $0.showtimes.map { $0.theatre.name }}.reduce([]) { $0 + $1 }
let uniqueNames = Array(Set(allNames))
The shows.map iterates through each Shows in shows. The inner map in turn iterates each Theatre in each of those Shows returning its name. So the inner map gives an array of names. The first map results in an array of arrays of names. The reduce merges those arrays of names into a single array of names leaving allNames with a single array containing every name.
The use of Array(Set(allNames)) first creates a unique set of the names and then it creates an array from that set.
If you want the final result to be sorted alphabetically then add .sorted() to the end.
If you need to keep the original order you can make use of NSOrderedSet and remove any use of sorted.
let names = NSOrderedSet(array: shows.map { $0.showtimes.map { $0.theatre.name }}.reduce([]) { $0 + $1 }).array as! [String]

Passing image from collectionview(based on json)

I have 2 json responses in this format...
//1 {
"product_id": "22",
"product_name": "asd",
"product_description": "Test",
"rating_count": 0,
"product_images": [
{
"id": "973",
"image": "http://myappp.com/uploads/products/16_546_4_image",
"is_default": "0"
},
{
"id": "988",
"image": "http://myappp.com/uploads/products/123_45_67_image",
"is_default": "0"
},
{
"id": "989",
"image": "http://myappp.com/uploads/products/123_45_6_image",
"is_default": "1"
}
]
},
//2 {
"product_id": "5",
"product_name": "cake",
"product_description": "The boss and Anchor Hocking are you doing today hope",
"rating_count": 0,
"product_images": [
{
"id": "962",
"image": "http://myappp.com/uploads/products/123_546_image",
"is_default": "1"
}
]
}
These are associated with 2 collectionview cells. Here I have an array called product_images with some parameters. Now I have a collectionview on which I'm displaying only those images from the url which have an is_default value of 1. I'm doing it like so...
for anItem in productData {
var productImages :[ProductImage] = [] //ProductImage is a struct having parameters myid, url and isDefault
if let images = anItem["product_images"] as? [[String:String]] {
if let defaultImage = images.first(where: {$0["is_default"] == "1"}) {
let productImage = ProductImage(myId: defaultImage["id"]!,
url: URL(string: defaultImage["image"]!)!,
isDefault: true)
productImages.append(productImage)
} } }
So if a collection view item shows an image then that image has an is_default value of 1. But each cell will also have associated with it the other images also with is_default value of 0 and other parameters like product_id, product_name etc. But only thing is what is shown in the collection view is the image with an is_default value of 1.
Now what I want to achieve is when I click on a collectionview cell I want to pass to another view not just the image shown on the cell but also the other images associated with a cell with an is_default value of 0. So if have 2 collectionview cells and each of them has the values of 1st and 2nd json(given above) respectively, then on the click of the first collectionviewcell I should be able to show 3 images and on the click of the 2nd collectionviewcell I should be able to show just 1 image.
Hope somebody can help...

Swift - Update an array of NSDictionary with values from another NSDictionary

Basically, I have an NSarray of dictionaries coming as a JSON response only once when view appears. Now, I need to update a particular value of a key in those dictionaries with another set of dictionary coming separately in every few second such that I can update my array of dictionaries continuously with those values and show some realtime set of data on the screen.
Example: This is the array of dictionary I am getting from backend
[
{item_id: 1001, name: "Apple", current_price: "$10"},
{item_id: 1009, name: "Orange", current_price: "$15"},
{item_id: 1004, name: "Mango", current_price: "$5"}
]
Current price is something which varies continuously, whose data I am receiving in NSDictionary format separately.
["1009": "$16", "1004": "$3", "1001": "$11"]
As you can see the new NSDictionary is mapped with the item_id to the current price value.
I need a way out to make sure the current price gets updated from this NSDictionary to the array of dictionary so that I can reuse that array to reload my UITableview and show the updated realtime price.
You can do it like this:
let items = [["item_id": 1001, "name": "Apple", "current_price": "$10"], ["item_id": 1009, "name": "Orange", "current_price": "$15"], ["item_id": 1004, "name": "Mango", "current_price": "$5"]]
let prices = ["1009": "$16", "1004": "$3", "1001": "$11"]
let updatedItems = items.map { itemDict -> [String: Any] in
var updatedItem = itemDict
if let idKey = itemDict["item_id"] as? Int {
prices["\(idKey)"].flatMap { updatedItem["current_price"] = $0 }
}
return updatedItem
}

appending JSON data?

I want to append my JSON data for sending to server..
I have this code
var json = JSONSerializer.toJson(data2)
and this is my data2
var data2 = Activitiesdata (type: leftlabel.text!, amount: qtytext.text.toInt()!)
and this is my Activitiesdata
class Activitiesdata
{
var type = "type"
var amount = 0
init (type: String, amount: Int)
{
self.type = type
self.amount = amount
}
}
when I click on a icon (lets say softball) and I println the outcome like this
{"type": "Softball", "amount": 90}
but whenever I click another icon, the outcome like this
{"type": "Badminton", "amount": 60}
how to append the data? so that the outcome like this whenever I click the second button and so on..
{"type": "Softball", "amount": 90} {"type": "Badminton", "amount": 60}
or is it possible to make like this
{"type": "Softball", "amount": 90, "type": "Badminton", "amount": 60} // (only 1 bracket)
thanks
using array is a good idea, but I always get compile error .. please help thanks
You put not enough information to answer, but it looks like you create json object every time you press the button, that's why the old value in a variable var json is replaced by a new one. You must first create an array of the objects and then serialize it into json.
Your JSON result will looks somthing like this:
{[{"type": "Softball", "amount": 90}, {"type": "Badminton", "amount": 60}]}
I do not know what mechanism you use to serializing, but if it write in the style in which it is written in your code, it will be something like this:
var dataArray: [Activitiesdata] = []
// click on a icon
let firstElement = Activitiesdata (type: leftlabel.text!, amount: qtytext.text.toInt()!)
dataArray.append(firstElement)
// click another icon
let secondElement = Activitiesdata (type: otherlabel.text!, amount: otherText.text.toInt()!)
dataArray.append(secondElement)
// serialize array to json in your style
var json = JSONSerializer.toJson(dataArray)
There is a good library for working with JSON - https://github.com/SwiftyJSON/SwiftyJSON

Resources