Any possibility to get all results of a specific key from json file?

Is this possible without SwiftyJSON or other frameworks? Im trying to understand if keyDecodingStrategy is the solution, or if there is another.

  let fileManager = FileManager.default
    let documentsURL = fileManager.urls(for: .documentDirectory, in: .userDomainMask)[0]
    do {
        let fileURLs = try fileManager.contentsOfDirectory(at: documentsURL, includingPropertiesForKeys: nil)
        
        for url in fileURLs {
            print(url) // <- that is the place for processing the urls
            let data = try Data(contentsOf: url)

                print(data)

            }
        }
    } catch {
        print("Error while enumerating files \(documentsURL.path): \(error.localizedDescription)")
    }

If I'm understanding your question correctly, It should certainly be possible to use JSONDecoder to do this.

You can write a struct that only includes the key you actually care about extracting. For example, if I had a bunch of JSON files, each one formatted like this:

{"someStringField": "x", "someIntField": 1}

And I only wanted to collect the "someStringField" values, I could write a Decodable struct that looks like this:

struct MyJSONData: Decodable {
    let someStringField: String
}

I can get a specific instance and the desired field with

let s = try JSONDecoder().decode(MyJSONData.self, from: data)
let str = s.someStringField

The decoder only cares that all the properties of MyJSONData are present in the data. It does not care if all of the key/value pairs in the data are present in MyJSONData.

1 Like

Thanks for your answer, but in my case it is not working well.

**Error loading data from disk keyNotFound(CodingKeys(stringValue: "type", intValue: nil), Swift.DecodingError.Context(codingPath: [_JSONKey(stringValue: "Index 0", intValue: 0)], debugDescription: "No value associated with key CodingKeys(stringValue: \"type\", intValue: nil) (\"type\").", underlyingError: nil))**

The Json structure is something like this:

[{"name”:”PLAYLISTNAME”, 
			”objects":[{ "group":"LIVE:",
					"title”:”Channel 1”, 
					”type":"LiveChannel", 
					"url”:”URL”,
					 "logo”:”LOGO” }] …

There are multiple playlists and want I want to archive is to get the type of the objects from all playlists.
Right now I'm able to get the type of objects from a selected playlist at a time by using this code:

class Playlist: Equatable, Codable {
    
    init(name: String, objects: [Object] = []) {
        self.name = name
        self.objects = objects
    }
    
    // MARK: Properties
    
    let name: String
    var objects: [Object]
}

func fileURL() -> URL {
    let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
    let documentsDirectory = paths[0]
    let filename = "playlists.json"
    let fullURL = documentsDirectory.appendingPathComponent(filename)
    return fullURL
}
func loadFromPersistentStore() -> [Playlist] {
    do {
        let data = try Data(contentsOf: fileURL())
        let jd = JSONDecoder()
        let playlists = try jd.decode([Playlist].self, from: data)
        return playlists
    } catch let error {
        print("Error loading data from disk \(error)")
    }
    return []
}

what does your implementation of Object look like? Should be something like this:

class Object: Decodable {
     let type: String // or an enum? see below  -  let type: ObjectType
    // ... and other properties
}

enum ObjectType: String, Decodable {
     case liveChannel = "LiveChannel"
     // and so on... 
}
class Object: Equatable, Codable {

    enum Group: String, Codable {
        case LiveChannel
        case TelevisionShow
        case Movie
        case unsupported
        
        static let allGroups: [Group] = [.LiveChannel, .TelevisionShow, .Movie, .unsupported]
    }
    
    init(type: Group.RawValue, title: String, group: String, url: String, logo: String) {
        
        self.type = type
        self.title = title
        self.group = group
        self.url = url
        self.logo = logo
    }

    // MARK: Properties
    let type: String
    let title: String
    let group: String
    let url: String
    let logo: String
}

The problem is that I can just get info from one playlist at a time:
static func objectsByType(playList: Playlist, type: Group) -> [Object] {

return playList.objects.filter{ $0.type == type.rawValue }

}

How can I do something like => allplaylists.objects.filter{ $0.type == type.rawValue }

This will return an array of all the objects in the playlist matching a type with that rawValue. You can then iterate over that array and use these Objects however you like. I'm sorry, I think I'm having trouble understanding what you're trying to accomplish.

Yes, it returns all objects from one selected playlist, but the Json file contains few playlists. The goal is to return all objects from all playlists.

Sorry, I'm on the road so I may have a few typos. But what you have is almost there. You need a function that takes an array of playlists and collects all objects that contain that particular type.

func objectsByType(playLists: [Playlist], type: Object.Group) -> [Object] {

var found: [Object] = []
for list in playLists {
    let objectsMatchingType = list.objects.filter { $0.type == type.rawValue }
   found.append(contentsOf: objectsMatchingType)
 }

 return found
}
1 Like

Or you could flatMap:

func objectsByType(playLists: [Playlist], type: Object.Group) -> [Object] {

    return playLists
        .flatMap { $0.objects } // gives me an array of all objects from all playlists
        .filter { $0.type == type.rawValue } // filter it to get the type you look for
}
1 Like

It worked great until I decided to convert the way I store to CoreData, now I get multiple errors.

func objectsByType(playList: Playlist, type: Object.ObjectType) -> [Object] {
    
    return playList.objects.filter{ $0.type == type.rawValue }
}

Value of type 'Any' has no member 'type'
Cast 'Any' to 'AnyObject' or use 'as!' to force downcast to a more specific type to access members

I think you'll need to post more of the code give us some context here

I found the solution :slight_smile:

    // Request Items with type = Movie
    let request: NSFetchRequest<Item> = Item.fetchRequest()
    request.predicate = NSPredicate(format: "type = %@", Item.ObjectType.Movie.rawValue)
    allMovies = try! CoreDataStack.context.fetch(request)
Terms of Service

Privacy Policy

Cookie Policy