I need to identify items of interest nearby to a particular latitude/longitude. I have two sets of objects stored in Core Data:
PostalArea
- latitude
- longitude
- postcode
Store
- name
- latitude
- longitude
I need to be able to retrieve a record from the PostalArea table, and then find stores which are closeby.
Most of the examples I've found are SQL based. I'm hoping someone can assist me with getting this working with Core Data. Ideally I would like to limit the result set to a certain number (say, 10), as opposed to limiting it based on distance.
EDIT: pulling all the records into memory is an option, if need be.
The most common solution to this is to determine a min/max of both lat and long and then do a predicate based on those. That would narrow your search to within a circle and then with those remaining objects in memory you can sort by closest to the point.
Update
Once you have the objects in memory you can then do some fun things with them. For instance you could have a transient value called 'currentPoint' and you could then KVO on the resulting array such as:
[resultingArray setValue:aPoint forKey:#"currentPoint"];
Then you could have a method that returns the distance from that point which you can sort by.
That is one example, I am sure there are other ways but the general idea is to get a subset of locations into memory so that you can then calculate distance and finally sort.
How would you feel about a REST service option? Is you use the Google APIs, you can query for exactly those things. There are plenty of JSON interfaces available for Objective C.
Related
I have a large databases of objects where I'd like to show objects that are nearer to the user searching first so I'm using aroundLatLngViaIP.
This works well for objects that are near by, however, if there aren't any nearby it doesn't show any further away even if there is an exact text match.
Is it possible to use aroundLatLngViaIP to promote results nearby but not exclude those that are far away?
To achieve this, you need to use aroundRadius: all as an additional query parameter. Quoting from the doc:
The special value all causes the geo distance to be computed and taken into account for ranking, but without filtering; this option is faster than specifying a high integer value.
https://www.algolia.com/doc/api-reference/api-parameters/aroundRadius/
I am working with an interesting scenario that I am not sure can work, or will work well. With my current project I am trying to find an efficient way of working with geopoints in firestore. The straight forward approach where a document can contain a geopoints field is pretty self explanatory and easy to query. However, I am having to work with a varying amount of geopoints for a single document (Article). The reason for this is because a specific piece of content may need to be available in more than one geographic area.
For example, An article may need to be available only in NYC, Denver and Seattle. Using a geopoint for each location and searching by radius, in general, is a pretty standard task if I only wanted the article to be available in Seattle, but now it needs to be available in two more places.
The solution as I see it currently is to use an array and fill it with geopoints. The structure would look something like this:
articleText (String),
sortTime (Timestamp),
tags (Array)
- ['tagA','tagB','tagC','tagD'],
availableLocations (Array)
- [(Geopoint), (Geopoint), (Geopoint), (Geopoint)]
Then performing a query to get all content within 10 miles of a specific Geopoint starting at a specific postTime.
What I don't know is if putting the geopoints in an array works well or should be avoided in favor or another data structure.
I have considered replicating an article document for each geopoint, but that does not scale very well if more than a handful of locations needs defining. I've also considered creating a "reference" collection where each point is a document that contains the documentID of an article, but this leads to reading each reference document then reading the actual document. Essentially two document reads for 1 piece of content, which can get expensive based on the Firestore pricing model, and may slow things down unnecessarily.
Am I approaching this in an acceptable way? And are there other methods that can work more efficiently?
Hi to the SO community !
I'm using Algolia Places to get some addresses to suggest to our end-users when they start to type their addresses in a field on our mobile-app.
So far it works well, I'm able to get places from all around the world.
But when I specify "aroundLatLng" and "aroundRadius" parameters, I just have a few places around the client's position.
Based on the documentation :
If you specify an aroundLatLng query parameter or if your source IP address is geo-localized, results will be composed by:
Places around you (<10km),
Places in your country,
Popular places all around the world.
I thought that specifying an "aroundRadius" parameter would just override the former "10km" default value, and still show some places from my country. In fact, it seems that specifying this parameter overrides completely the default fallback behavior which searches all over my country if it can't find anything relevant around me.
Is there any way to tell Algolia Places to increase the "10km" default radius while keeping the default behavior ? (i.e. still searching everywhere in my country)
Thanks a lot for your help !
Places team here 👋
aroundLatLng will just bias the results, to get a better relevancy of the results for this specific user. If we can't locate it or if there isn't any match, we will always return results anyway. See this a small weight on results around the user.
Whereas aroundRadius is a filter, meaning that we will only search and return results inside the radius area with aroundLatLng as the center.
There is no way to change the value of this '10km' "weight" since it's the inner workings of the algorithm. And by experience, this is more than enough to provide relevant results.
Let me know if it makes sense and if you have other questions!
I have store various latitude and longitude in database(Sqlite3) for various location. Now I have current latitude and longitude. How can I know nearest locations from current position.
Please suggest.
I assume you're talking about Reverse Geocoding. There's an Apple class provided for that, MKReverseGeocoder. There are also plenty of how-to discussions about that, such as here, here, etc.
The syntax will likely need to change, but take a look at this question that uses MySQL. Essentially you want to create a rectangle with the current point at the center (most likely). Using the bounds of this new box, you can run your SQL query.
I dare say #Kongress answer is the best here - but I'm just going to chuck this one into the ring as the concept itself is one that I've dealt with before.
I can't tell you how to build one in objective-c, but for our lat/long reverse lookup I built a K-DTree from the lat longs in our database ( > 250,000) and it gives us sub-100-nanosecond lookups on desktop hardware. On an iphone it's still likely to be pretty fast - memory might be a concern though as you really need to be able to cache the instance in memory, to be really useful; it takes a little while to build it (ours builds in about 1.5 seconds).
Just an idea.
I have a coredata based iphone app and have an Entity that has latitude and longtitude as properties. How can I return all my entities ordered by distance from the current location? I previosuly did this without coredata writing a sql query, but am new to coredata and can't figure it out. I would like to use the NSFetchedResultsController to pass straight to my tableview.
Any help please?
In my experience the best way to do this is to compute the distance of every single entry on first load (or location change) and save that property to CoreData, that way you can easily fetch entries using the distance property.
Here's a code snippet that calculates distance between 2 sets of coordinates:
for(SWShow *show in shows) {
CLLocation *showLocation = [[CLLocation alloc] initWithLatitude:show.latitude longitude:show.longitude];
double distance = [currentLocation distanceFromLocation:showLocation]/1000 // in km
show.distance = #(distance);
}
[managedObjectContext save];
I have a similar situation - and although the above is true with regards to not being able to use the NSFetchedResultsController you can still use core data to retrieve your data.
I also used sqlite3 before - and my fetch was done as a series of fetches of increasing bounding box sizes - until a size is reached where I have 'enough' results. In my case I double the latitude and longitude span for every iteration - giving approx. a quadrupling of the area for each iteration.
This method works fine in Core Data too - but as it is also stated above you need to copy the objects into a new array and sort them using your own method after the fetch is done.
Well, here's the problem: when you execute an NSFetchRequest, you can only base the predicate on persistent properties. It seems exceedingly unlikely you would have a persistent property that tracks the distance from the current location.
You could add a transient property to your entity that gives the distance from some globally defined location. You'd have to do a fetch request that gets all the objects, and then order them by this transient property.
If you have a lot of objects, you run the risk of filling up your memory quite quickly. And even if you don't, you'll still end up wasting time fetching objects you're never going to use.
I'm guessing you probably had a nifty SQL SELECT statement that computed the current distance in your previous version. You're not going to be able to replicate that with Core Data.