How to Geospatial Query in ObjCMongoDB - iphone

I'm trying to implement this query in ObjCMongoDB:
db.<collection>.find( { loc :
{ $near :
{ $geometry :
{ type : "Point" ,
coordinates : [ -121.9 , 37.5 ] } ,
$maxDistance : 10000
} } } )
However, I'm not receiving any queries (when I should) . Not sure what I'm doing wrong. Here's my attempt:
MongoKeyedPredicate *predicate = [MongoKeyedPredicate predicate];
NSValue *value = [NSValue valueWithCGPoint:CGPointMake(-121.9, 37.5)];
CGPoint point = [value CGPointValue];
CGFloat maxDistance = 10000;
[predicate keyPath:#"loc" isNearPoint:point maxDistance:maxDistance];
NSArray *results = [collection findWithPredicate:predicate error:&error];
for (BSONDocument *resultDoc in results) {
NSDictionary *result = [BSONDecoder decodeDictionaryWithDocument:resultDoc];
NSLog(#"fetch result: %#", result);
}

Related

Re-arrange NSArray and NSDictionary entries

I have array with nsdictionary objects, for ex.:
({"someKey" = "title";
"name" = "someName";
},
{"someKey" = "title";
"name" = "anotherName";
}
{"someKey" = "newTitle";
"name" = "someName";
}
)
Please, help me to sort it in this format:
({"someKey" = "title";
"names": (
{"name" = "someName"},
{"name" = "anotherName"}
)
},
{"someKey" = "newTitle";
"names": (
{"name" = "someName"}
)
}
)
Thanks..
As far as i understand from your question you want to pick individual objects into one single dictionary object..
NSArray *yourArray=.... /* array which contains this data: ({"someKey" = "title";
"name" = "someName";
},
{"someKey" = "title";
"name" = "anotherName";
}
)*/
NSMutableDictionary *newDictionary=[[NSMutableDictionary alloc]init];
for(int i=0;i<[yourArray count];i++){
[newDictionary setObject:[yourArray objectAtIndex:i] forKey:#"names"];
}
({"someKey" = "title";
"name" = "someName";
},
{"someKey" = "title";
"name" = "anotherName";
}
)
Assuming above is equivalent to
NSArray *array=[NSArray arrayWithObjects:dictionary1,dictionary2,nil];
then to achieve below result
(
{
"someKey" = "title";
"names": (
{"name" = "someName"},
{"name" = "anotherName"}
)
}
)
We have this :
//Get name array
NSMutableArray *names=[NSMutableArray array];
for(int i=0;i<[array count];i++)
{
NSDictionary *dictionary=[array objectAtIndex:i];
[names addObject:[dictionary valueForKey:#"name"];
}
NSDictionary *newDictionary=[NSDictionary dictionaryWithOjbectsAndKeys:#"someKey",#"title",names,#"names",nil];
//Your final result is an array with one object ( A Dictionary )
NSArray *finalArray=[NSArray arrayWithObjects: newDictionary,nil];
You just need to traverse the current structure and build a new dictionary with the title as the unique key:
NSEnumerator* arrayEnumerator = [myArray objectEnumerator];
NSDictionary* = dictFromArray;
NSMutableArray* titleArray = [[NSMutableArray alloc] init];
NSMutableDictionary* titleDict = [[NSMutableDictionary alloc] init];
while(dictFromArray = [arrayEnumerator nextObject])
{
currentTitle = [dictFromArray objectForKey:#"someKey"];
currentName = [dictFromArray objectForKey:#"name"];
if([titles containsObject:currentTitle)
{
NSMutableDictionary namesArray = [titleDict objectForKey:currentTitle];
[namesArray addObject:currentName];
}
else
{
[titles addObject:currentTitle];
[titleDict addObject:[NSMutableArray arrayWithObject:currentName] forKey:currentTitle];
}
}
This should give you a dictionary that looks like:
{
title =
(
someName,
anotherName
);
newTitle =
(
someName
)
}
To get the exact structure you have above, I think this should work:
NSArray* titleKeys = [titleDict allKeys];
NSEnumerator* keyEnumerator = [titleKeys objectEnumerator];
NSMutableArray* finalArray = [[NSMutableArray alloc] init];
NSString* key;
while (key = [keyEnumerator nextObject])
{
[finalArray addObject: [NSDictionary
dictionaryWithObjects:(key, [dictArray objectForKey:key])
forKeys:(#"someKey", #"names")]];
}

JSON Parsing. value not comes in Kilometers

i am new programmer.i am using Google Matrix API. i get the following response i wants fetch "text" : "1686 km". i am using Json Parsing. Thanks
"destination_addresses" : [ "San Francisco, Californie, États-Unis" ],
"origin_addresses" : [ "Vancouver, BC, Canada" ],
"rows" : [
{
"elements" : [
{
"distance" : {
"text" : "1 686 km",
"value" : 1685690
},
"duration" : {
"text" : "3 jours 21 heures",
"value" : 336418
},
"status" : "OK"
}
]
}
],
"status" : "OK"
}
SBJsonParser *json = [[SBJsonParser new] autorelease];
NSError *jsonError;
parsedJSON = [json objectWithString:data error:&jsonError];
Well, parsedJSON will be an NSDictionary so:
NSArray *rows = [parsedJSON objectForKey:#"rows"];
for (NSDictionary *row in rows) {
NSArray *elements = [row objectForKey:#"elements"];
for (NSDictionary *element in elements) {
NSDictionary *distance = [element objectForKey:#"distance"];
NSString *kmDistance = [distance objectForKey:#"text"]; ///< That's what you wanted
}
}

iPhone: Sorting based on location

I have been working on an iPhone app, where-in i have list of users in a NSMutableArray like below.
myMutableArray: (
{
FirstName = Getsy;
LastName = marie;
Latitude = "30.237314";
Longitude = "-92.461008";
},
{
FirstName = Angel;
LastName = openza;
Latitude = "30.260329";
Longitude = "-92.450414";
},
{
FirstName = Sara;
LastName = Hetzel;
Latitude = "30.2584499";
Longitude = "-92.4135357";
}
)
I need to sort users based on the location who is nearby to my location by calculating latitude and longitude. I am not able to achieve this till now. Could someone help me on giving some samples?
UPDATED: I am trying like below as per Mr.sch suggested. Please check my updated code. Is it fine?.
NSArray *orderedUsers = [myMutableArray sortedArrayUsingComparator:^(id a,id b) {
NSArray *userA = (NSArray *)a;
NSArray *userB = (NSArray *)b;
CGFloat aLatitude = [[userA valueForKey:#"Latitude"] floatValue];
CGFloat aLongitude = [[userA valueForKey:#"Longitude"] floatValue];
CLLocation *participantALocation = [[CLLocation alloc] initWithLatitude:aLatitude longitude:aLongitude];
CGFloat bLatitude = [[userA valueForKey:#"Latitude"] floatValue];
CGFloat bLongitude = [[userA valueForKey:#"Longitude"] floatValue];
CLLocation *participantBLocation = [[CLLocation alloc] initWithLatitude:bLatitude longitude:bLongitude];
CLLocation *myLocation = [[CLLocation alloc] initWithLatitude:locationCoordinates.latitude longitude:locationCoordinates.longitude];
CLLocationDistance distanceA = [participantALocation distanceFromLocation:myLocation];
CLLocationDistance distanceB = [participantBLocation distanceFromLocation:myLocation];
if (distanceA < distanceB) {
return NSOrderedAscending;
} else if (distanceA > distanceB) {
return NSOrderedDescending;
} else {
return NSOrderedSame;
}
}];
Thank you!
NSArray *orderedUsers = [users sortedArrayUsingComparator:^(id a,id b) {
User *userA = (User *)a;
User *userB = (User *)b;
CLLocationDistance distanceA = [userA.location getDistanceFromLocation:myLocation];
CLLocationDistance distanceB = [userB.location getDistanceFromLocation:myLocation];
if (distanceA < distanceB) {
return NSOrderedAscending
} else if (distanceA > distanceB) {
return NSOrderedDescending;
} else {
return NSOrderedSame;
}
}];
First thing, you will need to calculate the distance between your current location and the location of each other user.
Talking mathematically, here is a Wolfram|Alpha example
Now "programmatic-ally", you can use CLLocation class, here is an example:
(CLLocationDistance)getDistanceFrom:(const CLLocation *)location
But first you will need to create the location object from your Latitude and Longitude. You can use:
(id)initWithLatitude:(CLLocationDegrees)latitude longitude:(CLLocationDegrees)longitude
You can calculate the distance (geographical, not flat plane!) between your position and each of these items' positions and order by that value.
- (void)viewDidLoad {
[super viewDidLoad];
// This Array Taken Globally
List_of_locationsArray =[[NSMutableArray alloc]initWithObjects:
#{#"latitude" : #"17.415045",#"logitude":#"78.421424"} ,#{#"latitude" : #"17.415045",#"logitude":#"78.421424"},#{#"latitude" : #"17.415045",#"logitude":#"78.421424"},#{#"latitude" : #"17.415045",#"logitude":#"78.421424"},#{#"latitude" : #"17.415045",#"logitude":#"78.421424"}
,nil];
}
-(void)sortingLocationsArray{
// CLLocation* currentLocation =[[CLLocation alloc]initWithLatitude:[currentLatitude doubleValue] longitude:[currentLogitude doubleValue]];
CLLocation* currentLocation =[[CLLocation alloc]initWithLatitude: currentLatitudeHere longitude:CurrentLogHere];
NSMutableArray* tempLocationsArr = [[NSMutableArray alloc]initWithCapacity:[locationsArray count]];
for (int i=0; i<[locationsArray count]; i++) {
CLLocationDegrees latValue = [[locationsArray[i] objectForKey:#"latitude"] doubleValue];
CLLocationDegrees longValue = [[locationsArray[i] objectForKey:#"logitude"] doubleValue];
CLLocation* location = [[CLLocation alloc]initWithLatitude:latValue longitude:longValue];
[tempLocationsArr addObject:location];
NSArray* sortLocationArry = [tempLocationsArr sortedArrayUsingComparator:^NSComparisonResult(CLLocation* location1, CLLocation* location2) {
CLLocationDistance distA = [location1 distanceFromLocation:currentLocation];
CLLocationDistance distB = [location2 distanceFromLocation:currentLocation];
if (distA < distB) {
return NSOrderedAscending;
} else if ( distA > distB) {
return NSOrderedDescending;
} else {
return NSOrderedSame;
}
}];
//ArrayAfterSorting is another mutable Array to Store Sorting Data
[ArrayAfterSorting removeAllObjects];
[sortLocationArry enumerateObjectsUsingBlock:^(CLLocation* location, NSUInteger idx, BOOL *stop) {
NSMutableDictionary *tempDict = [[NSMutableDictionary alloc]init];
[tempDict setObject:[NSString stringWithFormat:#"%f",location.coordinate.latitude] forKey:#"latitude"];
[tempDict setObject:[NSString stringWithFormat:#"%f",location.coordinate.longitude] forKey:#"logitude"];
[ArrayAfterSorting addObject:tempDict];
}];
NSLog(#"sortedArray : %#", ArrayAfterSorting);
}
}
You may solve your problem in following way
1)Firstly store all above values in separate array Like latArray ,longArray,nameArray
2)Now get the distance between location(longArray,latArray) from your current location.
Then store these distances in separate Array(distanceArray).
//getDistance Between currentLocation and desired Location
-(void *)getDistanceFromCurrentLocation{
for(int val=0;val<[latArray count];val++){
NSString *dis_From_Current_Location;
dis_From_Current_Location =nil;
CGFloat str_Longitude=[[defaults objectForKey:#"long"]floatValue];
CGFloat str_Latitude=[[defaults objectForKey:#"lati"]floatValue];
//Suppose this is your current location
CGFloat lat1= [[latArray objectAtIndex:val]floatValue];
//these array for lat
CGFloat long1=[[longArray objectAtIndex:val]floatValue];
//these array for longArray
CLLocation *location1 = [[CLLocation alloc] initWithLatitude:lat1 longitude:long1];
CLLocation *location2 = [[CLLocation alloc] initWithLatitude:str_Latitude longitude:str_Longitude];
CLLocationDistance dist=[location1 distanceFromLocation:location2];
NSLog(#"Distance i meters: %f", [location1 distanceFromLocation:location2]);
long long v = llabs(dist/1000);
dis_From_Current_Location=[NSString stringWithFormat:#"%lld km",v];
[location1 release];
[location2 release];
[distanceArray addObject: dis_From_Current_Location];
//distanceArray is Global NsMutableArray.
}
}
Now You should Apply sorting method(selection, bubble) fro sorting the distances.
One thing need to care is that when you sort the distanceArray
please adjust values of nameArray as according to the distanceArray
See Below code for sorting the distanceArray and adjust the nameArray's value.
-(void)getSoretdArray{
NSString * tempStr,*tempStr2;
for(int i=0;i<[distanceArray count]; i++){
for(int j=i+1;j<[distanceArray count]; j++){
if([distanceArray objectAtIndex:j]>[distanceArray objectAtIndex:j+1]){
tempStr=[distanceArray objectAtIndex:j];
NSString* str= [distanceArray objectAtIndex:j+1];
[ distanceArray insertObject:str atIndex:j];
[distanceArray insertObject:tempStr atIndex:j+1] ;
//also change the name of corresponding location.
//you have to adjust the stored names in namArray for storing names of Corresponding Distances
tempStr2=[nameArray objectAtIndex:j];
NSString* str1= [nameArray objectAtIndex:j+1];
[ nameArray insertObject:str1 atIndex:j];
[nameArray insertObject:tempStr2 atIndex:j+1] ;
}
}
}
}
This will definitely work just try to use carefully

IOS JSON get all values from a "JSON Dict"

i have this data structure :
{
"artistlist " : [
{
"performer" : "Gate Zero"
},
{
"performer" : "nightech"
},
{
"performer" : "Marko Fuerstenberg"
},
]
}
I read this structure from NSString into NSDictionary with this line of code:
JSON = [NSJSONSerialization JSONObjectWithData:
[[chunks objectAtIndex:1]
dataUsingEncoding:NSUTF8StringEncoding] options:
NSJSONReadingMutableContainers error: &e];
with: [JSON objectForKey:#"artistlist "] i get this structure:
(
{
performer = "Gate Zero";
},
{
performer = nightech;
},
{
performer = "Marko Fuerstenberg";
}
)
Is there any way to go "deeper" ?
how would i parse the resulting Structure ?
I would like to get a list of values or access performer names directly. What if i have several values in a tupel for example performer name, album, year. How would i access those values?
Thank you.
Yes, after you have [JSON objectForKey:#"artistlist "], you get an NSArray of NSDictionaries (slightly confusing!).
NSArray *performersArray = [JSON objectForKey:#"artistlist"];
for (NSDictionary *performerDic in performersArray) {
NSLog(#"%#", [performerDic objectForKey:#"performer"]);
}
This should yield each performer name. Alternatively, you can do for (NSUInteger i = 0; i < [performersArray count]; i++) and access NSDictionary *performersDic = [performersArray objectAtIndex: i]. From there, you can similarly use [performsDic objectForKey:#"performer"]
Like this:
[[[JSON objectForKey:#"artistlist "] objectAtIndex: 1] objectForKey:#"performer"]
It will give you "nightech".
{} corresponds to NSDictionary, [] corresponds to NSArray.
You'll have to use recursion. For example, assuming you have only nested NSDictionaries (easy to modify to work with NSArrays):
- (void) getArtistFromJsonObject:(NSDictionary *)obj {
for (NSString *key in [obj allKeys]) {
id child = [obj objectForKey:key];
if ([child isKindOfClass:[NSString class]]) {
// that's the actual string
// NSLog(#"Found artist: %#", child); // or do whatever needed
} else if ([child isKindOfClass:[NSDictionary class]]) {
[self getArtistFromJsonObject:child];
}
}
}

Get 5 Nearest Annotations MKMapKit

I am using MKMapKit to get the nearest locations in a 100km radius. However I would like to know how I can sort the array into giving me the nearest five annotations at the top of the array.
My current code is:
CLLocation *currentlocation = [[CLLocation alloc] initWithLatitude:annotation.coordinate.latitude longitude:annotation.coordinate.longitude];
annotation.distanceToTarget = [currentlocation distanceFromLocation:usrlocation];
annotation.title = [dict objectForKey:#"name"];
annotation.subtitle = [NSString stringWithFormat:#"%#, %#, %#",[dict objectForKey:#"street"],[dict objectForKey:#"county"], [dict objectForKey:#"postcode"]];
annotation.subtitle = [annotation.subtitle stringByReplacingOccurrencesOfString:#", ," withString:#""];
if (annotation.distanceToTarget/1000 < 168) {
abc++;
NSLog(#"Distances Lower Than 168: %i", abc);
[storesLessThan100KAway addObject:annotation];
NSLog(#"Stores Count: %i", [storesLessThan100KAway count]);
}
for (int i = 0; i <= 5; i++) {
//NSLog(#"Stores Count For Loop: %i", [storesLessThan100KAway count]);
if ([storesLessThan100KAway count] > 5) {
[mapView addAnnotation:[storesLessThan100KAway objectAtIndex:i]];
}
}
Write your own compare method for annotations:
- (NSComparisonResult)compare:(Annotation *)otherAnnotation {
if (self.distanceToTarget > otherAnnotation.distanceToTarget) {
return NSOrderedDescending;
} else if (self.distanceToTarget < otherAnnotation.distanceToTarget) {
return NSOrderedAscending;
} else {
return NSOrderedSame;
}
}
Then you can sort using a selector:
NSArray *sortedArray = [storesLessThan100KAway sortedArrayUsingSelector:#selector(compare:)];
If you're using iOS4, you can use blocks to make this even easier:
NSComparator compareAnnotations = ^(Annotation *obj1, Annotation *obj2) {
if (obj1.distanceToTarget > obj2.distanceToTarget) {
return NSOrderedDescending;
} else if (obj1.distanceToTarget < obj2.distanceToTarget) {
return NSOrderedAscending;
} else {
return NSOrderedSame;
}
};
NSArray *sortedArray = [storesLessThan100KAway sortedArrayUsingComparator:compareAnnotations];