I am working in iOS using Swift. The service I am using returns the following JSON (cut off as the node begins to repeat):
{
"Ambler Departures: April 15, 2015, 2:57 pm": [
{
"Northbound": [
{
"direction": "N",
"path": "R5N",
"train_id": "564",
"origin": "Frazer Yard",
"destination": "Colmar-Link Belt",
"status": "On Time",
"service_type": "LOCAL",
"next_station": "North Broad St",
"sched_time": "Apr 15 2015 03:27:00:000PM",
"depart_time": "Apr 15 2015 03:27:00:000PM",
"track": "2",
"track_change": null,
"platform": " ",
"platform_change": null
},
{
"direction": "N",
"path": "R5N",
"train_id": "6566",
"origin": null,
Notice that the root node is created dynamically by the service-- I don't have a way of knowing what it will be as the user can chose departures from one of fifty stations and the time is based on the time on the server, which is likely inconsistent with the time on the user's clock.
I want to extract the data from the Northbound Array, and then a Southbound Array lower in the JSON.
I am getting the data returned form the service but I can't parse correctly. I can't get past the root node (the dynamic one) to get to the structure inside.
Here's what I am trying:
let json = JSON(data:data)
var x = 0
while x < json.count
{
let track = json[0]["Northbound"][x]["track"].string
println(track)
x++
}
This results in "nil". I am stuck...
I know that json[0] is probably wrong since that level of the JSON is not an array. Thanks in advance
If json is a JSON object from SwiftyJSON but you know it's a dictionary with an unknown key, you can find this key with:
let theKey = json.dictionary!.keys.first
Then access the array:
let theArray = json[theKey] as! [[String:AnyObject]] // array of dictionaries
Then theArray[0] will be the dictionary with "Northbound" as a key, which contains an array of dictionaries containing the infos.
(Edited to reflect the correct answer specific to SwiftyJSON.)
Related
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
}
}
How can I read this type of json data like I want profession of ID:12311 in google spreadsheet?
{
"user": [
{
"id": 12311,
"name": "Deffy doof",
"profession": "Photographer"
},
{
"id": 18341,
"name": "John Smith",
"profession": "Developer"
}
]
}
Solution:
Since this is an array of objects you can reference elements using array notation, e.g., to pull "Photographer":
data.user[0].profession
Sample:
If you only know the unique ID and not the index, you can filter the array first, then get the element.
var array = data.user.filter(function b(e) { return e.id == 12311 });
console.log(array[0].profession);
References:
filter()
Here I need to get the index of particular array in which the key value pair item.defaultShipping == "true" then I need to the get the index of particular array and to pass in model class so that in order to get corresponding data so that it should be passed in another Api but when I tried below method it showing an error that Contexual type 'Any' cannot be used within dictionary literal in let parameters below line can anyone help me how to resolve this issue ?
here is my code
var i = 0
for item in customerShippingAddressModel {
if item.defaultShipping == "true" {
}
i += 1
}
let arr = customerShippingAddressModel[i]
let parameters : [String: Any] = ["address":
[ "region": "\(arr.region.region)",
"region_code": "\(arr.region.regionCode)",
"region_id": "\(arr.region.regionId)",
"country_id": "\(arr.countryId)",
"company": "\(arr.company)",
"telephone": "\(arr.telephone)",
"postcode": "\(arr.postCode)",
"city": "\(arr.city)",
"firstname": "\(arr.firstName)",
"lastname": "\(arr.lastName)",
"email": "\(arr.email)",
"prefix": "",
"sameAsBilling": 1,
"street": ["0": "\((arr.customerStreet[0])!)",
"1": "\((arr.customerStreet[1])!)"]]]
print(parameters)
Since Swift 3 you can use enumerated() which will allow you to have the index and the value as the following:
for (index, item) in customerShippingAddressModel.enumerated() {
if item.defaultShipping == "true" {
// you can get the item and index value here.
}
}
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.
I have a Firebase that its structured as follows:
"zipcodes"
12345
1
"city": "test"
"state": "XX"
98765
2
"city": "test2"
"state": "AA"
3
"city": "test3"
"state": "BB"
I am trying to query my database by the user's zip code; however, when I try to view the snapshot that it found, it is null. Here is the code I currently have:
func firebaseSearch(zipCode: String) {
let conditionRef = FIRDatabase.database().reference().child("zipcodes")
let query = conditionRef.queryEqualToValue(zipCode)
query.observeSingleEventOfType(.Value, withBlock: {snapshot in
print(snapshot.value)
for child in snapshot.children {
print(child)
}
})
}
When I run the code, I get this:
(/zipcodes {
ep = 12345;
sp = 12345;
})
Optional(<null>)
My database has around 77k entries, so I was worried iterating through all entries and trying to find the child with my zipCode value would take a large amount of time, so I am trying to use the query feature to see if it's any quicker. I appreciate any help, thank you very much!
You don't need query for this, use .child(zipCode) instead of .queryEqualToValue(zipCode). That will return the expected result.
Hope this helps!!