I'm doing a GET request with RESTKit, and I need sone help mapping the JSON response.
Here is the response that I need to map:
{"limit_hit":false,"providers":
[{"id":876553,
"name":"Cooper, Bradley N, DDS",
"specialty_groups":["Other Provider"],
"tags":[],
"has_comments":false,
"number_of_comments":0,
"locations":
[{"address":"1234 Rifle Range Road, El Cerrito, CA, 94530",
"providers_at_address_count":1,
"client_product_count":0,
"non_client_product_count":2,
"address_lines":["1234 Rifle Range Road, El Cerrito, CA, 94530"],
"address_id":234578,
"specialty_groups":
[{"specialty_group":"Other Provider"}],
"provider_types":
[{"provider_type":"Other Provider"}]},
{"address":"7501 Mission Rd, Shawnee Mission, KS, 66208",
"providers_at_address_count":2,
"client_product_count":0,
"non_client_product_count":2,
"address_lines":["7654 Main S, El Cerrito, CA, 94530"],
"address_id":654432,
"specialty_groups":
[{"specialty_group":"Other Provider"}],
"provider_types":
[{"provider_type":"Other Provider"}]
}]
}]
}
I want to be able to map both addresses, but I don't know how. All I'm able to do currently is map the id, name, has_comments, and number_of_comments (I'm using the keypath of "providers").
Here is my current mapping provider:
+ (RKMapping *)searchMapping
{
RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[ProviderSearch class]];
[mapping addAttributeMappingsFromDictionary:#{
#"id": #"doctorID",
#"name": #"name",
}];
return mapping;
}
What exactly am I doing wrong, and how do I fix it?
Create another method to return the mapping for locations and then associate that mapping to this original one. Like this:
// ProviderLocation.m
+ (RKObjectMapping *)objectMapping
{
RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[ProviderLocation class]];
[mapping addAttributeMappingsFromDictionary:#{
#"address": #"address",
...
}];
return mapping;
}
Relationship:
+ (RKObjectMapping *)searchMapping
{
RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[ProviderSearch class]];
[mapping addAttributeMappingsFromDictionary:#{
#"id": #"doctorID",
#"name": #"name",
}];
RKObjectMapping *locationsMapping = [ProviderLocation objectMapping];
[mapping addPropertyMapping:
[RKRelationshipMapping relationshipMappingFromKeyPath:#"locations" toKeyPath:#"locations" withMapping:locationsMapping]];
return mapping;
}
Just remember to create a NSArray property in ProviderLocation.h named locations.
i've never used RKObjectMapping before but the "locations" you have there are an array of dictionary objects. so you would need an
NSArray loc = [myJson objectForKey:#"locations"];
for(NSDictionary *dict in loc){
//here each dict obj will have your "address", "providers_at_address_count" and etc... so if you want to access any of them you can call...
NSString *addr = [dict objectForKey:#"address"];
}
now somehow convert that to what you are doing with RXObjectMapping and you are golden =P
Related
I am creating a response descriptor for json to core data mapping in RestkitManager. The parent object is "level" and it has an array of "sublevel" objects.
RKDynamicMapping *levelMapping = [Level map];
RKResponseDescriptor* levelRd = [RKResponseDescriptor responseDescriptorWithMapping:levelMapping method:RKRequestMethodGET pathPattern:#"entity/:entityId" keyPath:#"summary.levels" statusCodes:RKStatusCodeIndexSetForClass(RKStatusCodeClassSuccessful)];
[self.objectManager addResponseDescriptor:levelRd];
In Level class
+ (RKEntityMapping *)mapping {
RKEntityMapping *mapping = [RKEntityMapping mappingForEntityForName:NSStringFromClass([self class]) inManagedObjectStore:[RKManagedObjectStore defaultStore]];
[mapping addAttributeMappingsFromDictionary:#{
#"id" : #"id",
#"name" : #"name",
#"state" : #"state"
}];
[mapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"sublevel" toKeyPath:#"sublevelList" withMapping:[Sublevel map]]];
return mapping;
}
In Sublevel
+ (RKEntityMapping *)map {
RKEntityMapping *mapping = [RKEntityMapping mappingForEntityForName:NSStringFromClass([self class]) inManagedObjectStore:[RKManagedObjectStore defaultStore]];
[mapping addAttributeMappingsFromDictionary:#{
#"id" : #"id",
#"staticNode.obj.name" : #"name"
}];
return mapping;
}
When I try to fetch sublevel on object level, I get it in random order. Sometimes 2nd sublevel get printed first. Is there any way to maintain the order?
As I understand, when mapping is done, I don't have any control over what is getting persisted in the database. Hence, I am not able to assign any order number myself. Apart from that, I have explored metadata.routing.parameters but for this I need to pass parameters in the API call itself - which is not desirable.
Any pointers on how to maintain the order would be helpful.
JSON
{
"entity": {
"id": 1,
"name": "name"
},
"settings": {
"key": "value"
}
}
Entity Model
Attributes: id, name
Relationship: settings(one to one)
Settings Model
Attributes: key
Relationship: entity(reverse relationship, one to one)
EntityMapping
RKEntityMapping *mapping = [RKEntityMapping mappingForEntityForName:NSStringFromClass([self class]) inManagedObjectStore:[RKManagedObjectStore defaultStore]];
mapping.persistentStore = [RKManagedObjectStore defaultStore].persistentStoreCoordinator.persistentStores.firstObject;
mapping.identificationAttributes = #[#"id"];
[mapping addAttributeMappingsFromDictionary:#{
#"id" : #"id",
#"name" : #"name"
}];
Had settings been inside entity in json response, I would add this
[mapping addPropertyMapping:
[RKRelationshipMapping relationshipMappingFromKeyPath:#"settings"
toKeyPath:#"settings" withMapping:[Settings map]]
];
But my response id different than this, so how should I map correctly?
Both entity and settings are in a container dictionary, so you can change your response descriptor to not drill down so far and then use key paths to drill into the entity part and have direct access to the settings part:
[mapping addAttributeMappingsFromDictionary:#{
#"entity.id" : #"id",
#"entity.name" : #"name"
}];
[mapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"settings" toKeyPath:#"settings" withMapping:[Settings map]]];
I have the following JSON:
"Menus":{
"Id" : "3",
"Name" : "Cheese Burger",
"Items": []
}
I map the response to Core Data like so:
+ (RKEntityMapping *)menuMapping {
RKEntityMapping *mapping = [RKEntityMapping mappingForEntityForName:#"Menu" inManagedObjectStore:[[CoreDataManager sharedInstance] objectStore]];
mapping.assignsNilForMissingRelationships = YES;
mapping.assignsDefaultValueForMissingAttributes = YES;
[mapping addAttributeMappingsFromDictionary:#{
#"Id": #"remoteID",
#"Name": #"name",
}];
mapping.identificationAttributes = #[ #"remoteID" ];
[mapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"Items"
toKeyPath:#"products"
withMapping:[MappingProvider productMapping]]];
return mapping;
}
+ (RKEntityMapping *)productMapping {
RKEntityMapping *mapping = [RKEntityMapping mappingForEntityForName:#"Product" inManagedObjectStore:[[CoreDataManager sharedInstance] objectStore]];
mapping.assignsNilForMissingRelationships = YES;
[mapping addAttributeMappingsFromDictionary:#{
#"Id": #"remoteID",
#"Name": #"name",
#"Description" : #"info",
#"Price": #"price"
}];
mapping.identificationAttributes = #[ #"remoteID" ];
return mapping;
}
How would I manage to validate if the Items array is empty or not, and create the Menu object in Core Data based on if the Items (the products) contains values? I have tried using the assignsNilForMissingRelationships but it does not seem to work in this case.
Use KVC validation to analyse the incoming value and (modify or) reject it.
how can i map nested objects of the same type?
i have an xml with objects that may contain multiple objects of the same type:
<entry location="l1">
<entry location="l1.1">
<entry location="l1.1.1">
</entry>
<entry location="l1.1.2">
</entry>
</entry>
</entry>
i get an infinite recursion if i add a propertymapping with the same mapping:
+ (RKObjectMapping *)objectMapping {
RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[Entry class]];
[mapping addAttributeMappingsFromDictionary:#{#"location": #"location"}];
[mapping addPropertyMapping:[RKRelationshipMapping relationshipMappingFromKeyPath:#"nextEntries"
toKeyPath:#"entries"
withMapping:[Entry objectMapping]]];
return mapping;
}
is it possible to add the sub-objects to an array of each parent object?
cheers
//edit: following code works for me:
+ (RKObjectMapping *)objectMapping
{
RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[Entry class]];
[mapping addAttributeMappingsFromDictionary:#{#"location": #"location"}];
RKObjectMapping *innerMapping = [RKObjectMapping mappingForClass:[Entry class]];
[innerMapping addAttributeMappingsFromDictionary:#{#"location": #"location"}];
[mapping addPropertyMapping:[RKRelationshipMapping
relationshipMappingFromKeyPath:#"entry"
toKeyPath:#"entries"
withMapping:innerMapping]];
return mapping;
}
I haven't tried it so I don't know if it will work but try this:
+ (RKObjectMapping *)objectMapping
{
RKObjectMapping *mapping = [RKObjectMapping mappingForClass:[Entry class]];
[mapping addAttributeMappingsFromDictionary:#{#"location": #"location"}];
RKObjectMapping *innerMapping = [RKObjectMapping mappingForClass:[Entry class]];
[innerMapping addAttributeMappingsFromDictionary:#{#"location": #"location"}];
[mapping addPropertyMapping:[RKRelationshipMapping
relationshipMappingFromKeyPath:#"nextEntries"
toKeyPath:#"entries"
withMapping:innerMapping]];
return mapping;
}
Not sure that toKeyPath:#"entries" is correct, it may need to be toKeyPath:#"entry" based on your XML.
The infinite recursion is because you're calling the same method from itself ([Entry objectMapping]), it has nothing to do with the mapping as such.
In RestKit for mapping a class to JSON key-value we use,
RKObjectMapping * userMapping = [RKObjectMapping mappingForClass:[User class]];
[userMapping mapKeyPath:#"PrimaryKey" toAttribute:#"id"];
[[RKObjectManager sharedManager].mappingProvider setMapping:usereMapping forKeyPath:#"clientUser"];
However in android, if restlet is used, we just have to add #JsonProperty("PrimaryKey"), when declaring the variable in the class. And the Key value mapping is done.
Is there a simpler way for iOS restkit similar to android restlet?
Thanks in advance.
You can do it like this in ios
RKObjectMapping* articleMapping = [RKObjectMapping mappingForClass:[Article class]];
[articleMapping addAttributeMappingsFromDictionary:#{
#"title": #"title",
#"body": #"body",
#"author": #"author",
#"publication_date": #"publicationDate"
}];
And
// Create our new Author mapping
RKObjectMapping* authorMapping = [RKObjectMapping mappingForClass:[Author class] ];
// NOTE: When your source and destination key paths are symmetrical, you can use addAttributesFromArray: as a shortcut instead of addAttributesFromDictionary:
[authorMapping addAttributeMappingsFromArray:#[ #"name", #"email" ]];
REFER HERE