How to build a RavenDB spatial index correctly and also check if any <objects> list matches?
Following an example on the RevenDB website , I came up with the following:
public class Place_ByLocationsAndCategoryId : AbstractIndexCreationTask<Place> { public Place_ByLocationsAndCategoryId() { Map = places => from p in places select new { p.Categories, _ = Raven.Database.Indexing.SpatialIndex.Generate(p.Location.Lat, p.Location.Lng) }; } }
The places look something like this:
Place { string Id; List<Category> Categories; ... }
Categories look something like this:
Category { string Id; string Name; ... }
How can I build my index so that I can query for places within a given lat / lng radius and contains a specific category?
I tried to query the index above:
var placesFromDb = RavenSession.Advanced.LuceneQuery<Place>("Place/ByLocationsAndCategoryId").WhereIn("Id", new []{cat.Id}).WithinRadiusOf(radius: 5, latitude: Lat, longitude: Lng).ToList<Place>();
The request process, but does not return results (when I know that there are results that will be returned. My error is probably in the .WhereIn()
statement, but when I tried to use .Where(x => x.Categories.Any(c => c.Id == id))
, I received a build error, indicating that it is deprecated.
- Update -
I switched my index to this (as Iyend recommended)
public Place_ByLocationsAndCategoryId() { Map = places => from p in places select new { Categories_Id = p.Categories.Select(x => x.Id), _ = Raven.Database.Indexing.SpatialIndex.Generate(p.Location.Lat, p.Location.Lng) }; }
I create an index in the document store as follows:
IndexCreation.CreateIndexes(typeof(Place_ByLocationsAndCategoryId).Assembly, Store);
I request it like this:
var placesFromDb = RavenSession.Advanced.LuceneQuery<Place>("Place/ByLocationsAndCategoryId").WhereEquals("Categories_Id ", cat.Id).WithinRadiusOf(radius: 15, latitude: Lat, longitude: Lng).ToList<Place>();
Here's what the index looks like on RavenDB itself:
docs.Places .Select(p => new {Categories_Id = p.Categories .Select(x => x.Id), _ = SpatialIndex.Generate(((System.Double)(p.Location.Lat)), ((System.Double)(p.Location.Lng)))})
The query works, but returns 0 results (I know there are places that can be found). One thing I noticed is that the Lat and Lng data types in my model are float, while the index is set to Double.
Trying to reset the coordinates to the index also does not work either:
public Place_ByLocationsAndCategoryId() { Map = places => from p in places select new { Categories_Id = p.Categories.Select(x => x.Id), _ = Raven.Database.Indexing.SpatialIndex.Generate((float)p.Location.Lat, (float)p.Location.Lng) }; }
So, I switched my model to using doubling; still returns 0 results.
- Update 2 -
If I remove part of the index category and request only the spatial part, it will return the places. It seems that part of the category does not function as planned.
In case this helps, here's how the stored document partially looks (kind of JSON):
{ "Id": "4dca6d56d22da18f4e626f54", "Name": "焼肉", "Categories": [ { "PlaceCategories": null, "Name": "Korean Restaurant", "Icon": "korean.png", "Id": "4bf58dd8d48988d113941735", "IsPrimary": true } ], "Location": { "Lat": "35.6709824", "Lng": "139.374588" }, ... }
(note: Categories are a list, categories can have subcategories in their own List property called PlaceCategories)
- Update 3 -
Here's a pointing error from the management studio:
Places/ByLocationsAndCategoryId Cannot convert type 'string' to 'float' 6/27/2012 places/1025 ... and repeats 50 times
I already changed my model from float to double, because it looked like the spatial generator wanted to double. There is a good chance that there are some errors in the log (it is not possible to view the last 50), indicating "Cannot convert the type" string "to" float "
I am curious that in my model, earlier my Lat / Lng was floating. Where did the line come from?
Turns out it was my model. For future reference, if you want to use spatial indexes in Raven, you must save your coordinates as double (mine were originally float). I changed the value twice, but I had to write a script to view all my documents in the database and convert the coordinates to double.
After that he worked as a champion.
You want it to be like this:
Index
public class Place_ByLocationsAndCategoryId : AbstractIndexCreationTask<Place> { public Place_ByLocationsAndCategoryId() { Map = places => from p in places select new { Categories_Id = p.Categories.Select(x=>x.Id), _ = Raven.Database.Indexing.SpatialIndex.Generate(p.Location.Lat, p.Location.Lng) }; } }
Query:
var placesFromDb = RavenSession.Advanced.LuceneQuery<Place>("Place/ByLocationsAndCategoryId").WhereEquals("Categories_Id ", cat.Id).WithinRadiusOf(radius: 5, latitude: Lat, longitude: Lng).ToList<Place>();