Deserialize Mantle object using two JSON formats - objective-c

Is there a way to construct a mantle object using two different JSON objects? For example, say there is an Address class and the following two JSON formats:
{
"street: "s",
"city" : "city",
"state" : "state",
"zipcode" "12345"
}
{
"street_one: "s1",
"street_two: "s2",
"apartment" : "apt 1",
"city" : "city",
"state" : "state",
"zip" "12345"
}
[MTLJSONAdapter modelOfClass:[Address class] fromJSONDictionary:JSONDictionary error:&error];
Is there somewhere in MTLJSONAdapter to recognize two formats and assign or serialize properties based on them?
+ (NSDictionary *)JSONKeyPathsByPropertyKey
{
if (isJsonV2) {
// do new mapping
}
else {
// do original mapping
}
}
Hope to do something like above, or anything that allows conditionally mapping to the object.

Mantle doesn't support this, but you could use a subclass for V2 which has the extra street entry, or use a protocol to encapsulate the shared behaviour.

Related

Cloudant search document by attributes of nested objects

My documents in cloudant have the following structure
{
"_id" : "1234",
"name" : "test",
"objects" : [
{
"type" : "TYPE1"
"time" : "1215
},
{
"type" : "TYPE2"
"time" : "1115"
}
]
}
Now I need to query my documents by a list of types.
Examples
1) If I would query with TYPE1 then all the documents where there is an object with this type would return. (The example doc would return)
2) If I would query with TYPE1 and TYPE3 it would return all documents which contain either of them (The example doc would return)
3) If I would query with TYPE3, TYPE4 and TYPE5 it would return all documents which contain either of them (The example doc would not return)
How would the code in the _design document look like and how would my API request look like?
One option is to use Cloudant Search.
Sample design document named types, which indexes each type property in your objects array
{
"_id": "_design/types",
"views": {},
"language": "javascript",
"indexes": {
"one-of": {
"analyzer": "standard",
"index": "function (doc) {\n for(var i in doc.objects) {\n index(\"type\", doc.objects[i].type); \n }\n}"
}
}
}
Query examples:
Search for one key (type=val)
GET https://$HOST/$DATABASE/_design/$DDOC/_search/one-of?q=type%3ATYPE1
Search for multiple keys (type=val1 OR type=val2)
GET https://$HOST/$DATABASE/_design/$DDOC/_search/one-of?q=type%3ATYPE1%20OR%20type%3ATYPE2
Search for multiple keys (type=val1 AND type=val2)
GET https://$HOST/$DATABASE/_design/$DDOC/_search/one-of?q=type%3ATYPE1%20AND%20type%3ATYPE2
To include the documents in the response append &include_docs=true.

Mongo adding an object to original object

I am not sure if I am asking the correct question but I assume this is just a basic mongodb question.
I currently have this:
{
"_id" : ObjectId("57af98d4d71c4efff5304335"),
"fullname" : "test",
"username" : "test",
"email" : "test#gmail.com",
"password" : "$2a$10$Wl29i6FemBrnOKq/ZErSguxlfvqoayZQkaEDirkmDl5O3GDEQjOV2"
}
and I would like to add an exercise object like this:
{
"_id" : ObjectId("57af98d4d71c4efff5304335"),
"fullname" : "test",
"username" : "test",
"email" : "test#gmail.com",
"password" : "$2a$10$Wl29i6FemBrnOKq/ZErSguxlfvqoayZQkaEDirkmDl5O3GDEQjOV2",
"exercises": {
"benchpress",
"rows",
"curls",
}
I am just unsure how to create exercises with the object without using $push which just opens up an array. I don't want an array, I want an object.
Any help would be greatly appreciated it.
An object is a key-value pair. In your representation of the second document, you have a nested document exercises as a key and its value as an object containing only strings. Don't you see something strange there? An object without keys?
It should probably be an array of strings. Note that an array is indeed an object where the key is the numeric index starting from 0 and the value is the string in that position.
(You have an additional comma and a missing curly-brace. Lets fix that.)
This is the document we wish to see after updating the document.
{
"_id" : ObjectId("57af98d4d71c4efff5304335"),
"fullname" : "test",
"username" : "test",
"email" : "test#gmail.com",
"password" : "$2a$10$Wl29i6FemBrnOKq/ZErSguxlfvqoayZQkaEDirkmDl5O3GDEQjOV2",
"exercises": [
"benchpress",
"rows",
"curls"
]
}
Now, back to your question. How can we update the existing document with the exercises document? Its pretty simple. Mongodb has a 'update' method which exactly does that. Since we don't want to replace the entire document and just add additional fields, we should use $set to update specific fields. Fire up the mongo shell and switch to your database using use db-name. Then execute the following command. I assume you have an existing document with id ObjectId("57af98d4d71c4efff5304335"). Note that ObjectId is a BSON datatype.
db.scratch.update({ "_id" : ObjectId("57af98d4d71c4efff5304335") }, { $set: {"exercises": ["benchpress", "rows", "curls"] } })
This will update the document as
{
"_id" : ObjectId("57af98d4d71c4efff5304335"),
"fullname" : "test",
"username" : "test",
"email" : "test#gmail.com",
"password" : "$2a$10$Wl29i6FemBrnOKq/ZErSguxlfvqoayZQkaEDirkmDl5O3GDEQjOV2",
"exercises" : [
"benchpress",
"rows",
"curls"
]
}
Here scratch refers to the collection name. The update method takes 3 parameters.
Query to find the document to update
The Update parameter(document to update). You can either replace the whole document or just specific parts of the document(using $set).
An optional object which can tell Mongodb to insert the record if the document doesn't exist(upsert) or update multiple documents that match the criteria(multiple).
EXTRA
Warning: If you execute the following in the mongo shell,
db.scratch.update({ "_id" : ObjectId("57af98d4d71c4efff5304335") }, {"exercises": ["benchpress", "rows", "curls"] })
the entire document would be replaced except the _id field. So, the record would be something like this:
{
"_id" : ObjectId("57af98d4d71c4efff5304335"),
"exercises" : [
"benchpress",
"rows",
"curls"
]
}
You should only do this when you are aware of the consequence.
Hope this helps.
For more, see https://docs.mongodb.com/manual/reference/method/db.collection.update/

Proper formatting for Array within JSON from iOS using NSURLSessionDataTask

I'm trying to do a POST to a RESTful Web API and having issues with the format on the httpBody. NSJSONSerialization is creating this:
{
"UserId" : "ThisIsMe",
"Locations" : "[\n \"1\"\n]",
"TypeOfValue" : "3",
"SomeTypeID" : 22,
"Title" : "asdfadsf",
"Description" : "Description"
}
But what I need is this:
{
"UserId" : "ThisIsMe",
"Locations" : ["1"],
"TypeOfValue" : "3",
"SomeTypeID" : 22,
"Title" : "asdfadsf",
"Description" : "Description"
}
In order to put this together "as is" I had to take an NSArray run NSJSONSerialization on it then append that to an NSDictionary and then call NSJSONSerialization on that. So there is a problem obviously with the double serialization, but if I pass in the array with the NSDictionary it fails...help please.
You should have an NSDictionary whose keys are all strings and whose values are NSString, NSNumber or NSArray (containing NSString) instances. Then, use NSJSONSerialisation to convert that dictionary representation into a JSON data representation and you will get what you want.

MultiLevel JSON in PIG

I am new to PIG scripting and working with JSONs. I am in the need of parsing multi-level json files in PIG. Say,
{
"firstName": "John",
"lastName" : "Smith",
"age" : 25,
"address" :
{
"streetAddress": "21 2nd Street",
"city" : "New York",
"state" : "NY",
"postalCode" : "10021"
},
"phoneNumber":
[
{
"type" : "home",
"number": "212 555-1234"
},
{
"type" : "fax",
"number": "646 555-4567"
}
]
}
I am able to parse a single level json through JsonLoader() and do join and other operations and get the desired results as JsonLoader('name:chararray,field1:int .....');
Is it possible to parse the above mentioned JSON file using the built-in JsonLoader() function of PIG 0.10.0. If it is. Please explain me how it is done and accessing fields of the particular JSON?
You can handle nested json loading with Twitter's Elephant Bird: https://github.com/kevinweil/elephant-bird
a = LOAD 'file3.json' USING com.twitter.elephantbird.pig.load.JsonLoader('-nestedLoad')
This will parse the JSON into a map http://pig.apache.org/docs/r0.11.1/basic.html#map-schema the JSONArray gets parsed into a DataBag of maps.
It is possible by creating your own UDF. A simple UDF example is shown in below link
http://pig.apache.org/docs/r0.9.1/udf.html#udf-java
C = load 'path' using JsonLoader('firstName:chararray,lastName:chararray,age:int,address:(streetAddress:chararray,city:chararray,state:chararray,postalCode:chararray),
phoneNumber:{(type:chararray,number:chararray)}')

Parsing complex JSON using RestKit in Objective C

I've been having issues with this issue for several days now, and would really appreciate it if someone will be able to provide some guidance or even a full code solution for this.
I'm trying to perform dynamic object mapping to a JSON string in Objective C using RestKit and can't seem to get the right values.
This is an example to the kind of JSON response I need to parse:
{
"Boy" :
{
"favoriteClass" : "math",
"basicInfo" :
{
"name" : "John",
"age" : 10,
"type" : 1
}
"friends" :
[
{
"Boy" :
{
"favoriteClass" : "PE"
"basicInfo" :
{
"name" : "Bill",
"age" : 12,
"type" : 1
}
"friends" : []
},
"Girl" :
{
"favoriteTeacher" : "Mrs. Manson"
"basicInfo" :
{
"name" : "Sara",
"age" : 11,
"type" : 2
}
"friends" : []
},
"Girl" :
{
"favoriteTeacher" : "Mr. Chase"
"basicInfo" :
{
"name" : "Ronda",
"age" : 9,
"type" : 2
}
"friends" : []
}
}
]
}
}
Meaning, I have two types of classes: a Buy class and a Girl class.
They each have different fields (favoriteClass for the boys and favoriteTeacher for the girls), but the both have a basicInfo field, which contains exactly the same structure.
I can tell which should be mapped to the Boy class and which should be mapped to the Girl class with using the name of the record in the array ("Boy" or "Girl"), or by the "type" field's value within the "basicInfo" record (1 for boys and 2 for girls).
The friends array for both a Boy and a Girl class can contain instances of both boys and girls.
Can anybody please give me some pointers on how this can be done?
Any help will be greatly appreciated.
Thanks,
I just started looking at RestKit today, so I am far from an authority. However, looking at Blake's excellent documentation, it seems to me that you are overly complicating this (your posted JSON does not validate BTW). Unless you have a specific need to have a BasicInfo object, I'd remove it and configure your JSON thus:
{
"people": [
{
"age": 10,
"favoriteClass": "math",
"name": "John",
"type": 1,
"friends": [
{
"age": 12,
"favoriteClass": "PE",
"friends": [],
"name": "Bill",
"type": 1
},
{
"age": 11,
"favoriteTeacher": "Mrs. Manson",
"friends": [],
"name": "Sara",
"type": 2
},
{
"age": 9,
"favoriteTeacher": "Mr. Chase",
"friends": [],
"name": "Ronda",
"type": 2
}
]
}
]
}
Then you should be able to utilize approach (1) that he describes in the Dynamic Object Mapping section of the Object Mapping document. It appears to me that the only difference you have in comparison with the example he gives is that you have some additional ivars in each of the Boy and Girl classes, and you are using an number rather than a string to identify Boy vs Girl. You can deal with that by modifying the declarations he gives to be:
// Basic setup
RKObjectMapping* boyMapping = [RKObjectMapping mappingForClass:[Boy class]];
[boyMapping mapAttributes:#"age", #"name", #"favoriteClass",nil];
RKObjectMapping* girlMapping = [RKObjectMapping mappingForClass:[Girl class]];
[girlMapping mapAttributes:#"age", #"name", #"favoriteTeacher", nil];
// Configure the dynamic mapping via matchers
[dynamicMapping setObjectMapping:boyMapping whenValueOfKeyPath:#"type" isEqualTo:#"1"];
[dynamicMapping setObjectMapping:girlMapping whenValueOfKeyPath:#"type" isEqualTo:#"2"];
The type of the matcher may not be quite right -- as I said, I just started reading this stuff today.
Just go through the hierarchy in a disciplined way.
//pseudo code
for (id child in JSONObject) {
if (it is a boy) create new boy object;
else create new girl object;
fill in the info;
for (id child in friends) {
if (it is a boy) create new boy object;
else create new girl object;
fill in the info;
}
}
Of course the whole data scheme is ridiculously repetitive. In my opinion, you should have only one class Child that anyway has an attribute basicInfo.type that identifies it as boy or girl, so no need to have an extra class.
Also, if you have a list of children who are friends with each other, you will end up listing many children multiple times. Much better would be to have a simple array with unique IDs in the friends field.
You simply need to use a JSON parser like SBJSON, SBJSON can parse the data you receive like so:
SBJsonParser *parser = [[SBJsonParser alloc] init];
NSDictionary *received = [parser objectWithData:data];
However, if you want to use Restkit, it has a built in parser also. I believe it would work something like this:
- (void)request:(RKRequest*)request didLoadResponse:(RKResponse*)response
{
RKJSONParser* parser = [RKJSONParser new];
NSDictionary *dict = [parser objectFromString:[response bodyAsString]];
}
I hope that helps you.