This article was originally published at: https://www.ahmetkucukoglu.com/en/couchbase-geosearch-with-asp-net-core/
The subject of this article will be about how to do "GeoSearch" by using Couchbase.
1. Installing the Couchbase
For this purpose, we create Couchbase cluster with the docker by running the command below.
docker run -d --name couchbase -p 8091-8094:8091-8094 -p 11210:11210 couchbase
When Couchbase is up, it will start broadcasting at the address below.
We create the cluster by clicking the "Setup New Cluster" button. We define the password as "123456".
You can make adjustment according to your current memory status. You can turn off "Analytics". We complete the cluster installation by clicking the "Save & Finish" button.
We go to "Buckets" from the left menu, click the "Add Bucket" button at the top of the right corner and create a bucket called "meetup".
http://localhost:8091/ui/index.html#!/buckets
2. Creating the API
As an example, we will do the events section in the Meetup application that we all use. We will define events through the API. We will record the locations of these events. We will then query a list of events near by the current location.
We create an ASP.NET Core API project. We install the nuget packages below.
dotnet add package CouchbaseNetClient
dotnet add package Couchbase.Extensions.DependencyInjection
We add Couchbase connection information to the appsettings.json file.
{ | |
"Couchbase": { | |
"Username": "admin", | |
"Password": "123456", | |
"ConnectionString": "couchbase://localhost" | |
}, | |
"Logging": { | |
"LogLevel": { | |
"Default": "Information", | |
"Microsoft": "Warning", | |
"Microsoft.Hosting.Lifetime": "Information" | |
} | |
}, | |
"AllowedHosts": "*" | |
} |
We define Couchbase in the Startup.cs file.
namespace Couchbase.GeoSearchApp | |
{ | |
using Couchbase.Extensions.DependencyInjection; | |
using Microsoft.AspNetCore.Builder; | |
using Microsoft.AspNetCore.Hosting; | |
using Microsoft.Extensions.Configuration; | |
using Microsoft.Extensions.DependencyInjection; | |
using Microsoft.Extensions.Hosting; | |
public class Startup | |
{ | |
public Startup(IConfiguration configuration) | |
{ | |
Configuration = configuration; | |
} | |
public IConfiguration Configuration { get; } | |
public void ConfigureServices(IServiceCollection services) | |
{ | |
services.AddCouchbase(Configuration.GetSection("Couchbase")); | |
services.AddControllers(); | |
} | |
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) | |
{ | |
if (env.IsDevelopment()) | |
{ | |
app.UseDeveloperExceptionPage(); | |
} | |
app.UseRouting(); | |
app.UseEndpoints(endpoints => | |
{ | |
endpoints.MapControllers(); | |
}); | |
} | |
} | |
} |
2.1. Creating an CreateEvent Endpoint
In the project, we create a folder named "Models" and add a class named "EventDocument" into it. This class will be the model of the document that we will add to the bucket named "events" in Couchbase.
namespace Couchbase.GeoSearchApp | |
{ | |
using System; | |
public class EventDocument | |
{ | |
public string Subject { get; set; } | |
public DateTimeOffset Date { get; set; } | |
public string Description { get; set; } | |
public string Address { get; set; } | |
public EventLocationDocument Location { get; set; } | |
} | |
public class EventLocationDocument | |
{ | |
public double Lat { get; set; } | |
public double Lon { get; set; } | |
} | |
} |
Likewise, we add a class named "CreateEventRequest" under the "Models" folder. It will be the request model of endpoint, which will allow us to record this event.
namespace Couchbase.GeoSearchApp | |
{ | |
using System; | |
public class CreateEventRequest | |
{ | |
public string Subject { get; set; } | |
public DateTimeOffset Date { get; set; } | |
public string Description { get; set; } | |
public string Address { get; set; } | |
public double Latitude { get; set; } | |
public double Longitude { get; set; } | |
} | |
} |
We add a controller named "EventsController".
namespace Couchbase.GeoSearchApp.Controllers | |
{ | |
using Couchbase.Core; | |
using Couchbase.Extensions.DependencyInjection; | |
using Microsoft.AspNetCore.Mvc; | |
using System; | |
using System.Threading.Tasks; | |
[Route("api/[controller]")] | |
[ApiController] | |
public class EventsController : ControllerBase | |
{ | |
private readonly IBucket _bucket; | |
public EventsController(IBucketProvider bucketProvider) | |
{ | |
_bucket = bucketProvider.GetBucket("events"); | |
} | |
[HttpPost] | |
public async Task<IActionResult> CreateEvent([FromBody] CreateEventRequest request) | |
{ | |
var document = new Document<EventDocument> | |
{ | |
Id = Guid.NewGuid().ToString(), | |
Content = new EventDocument | |
{ | |
Subject = request.Subject, | |
Description = request.Description, | |
Date = request.Date, | |
Address = request.Address, | |
Location = new EventLocationDocument | |
{ | |
Lat = request.Latitude, | |
Lon = request.Longitude | |
} | |
} | |
}; | |
await _bucket.InsertAsync(document); | |
return Ok(); | |
} | |
} | |
} |
Now we can add events to Couchbase. Let's run the application and make requests from Postman as follows.
When we look at the documents of events bucket in Couchbase, we will see that it has been added.
http://localhost:8091/ui/index.html#!/doc_editor?bucket=events
2.2. Creating The Index That Allows Searching According To Location
In Couchbase, we come to "Search" from the left menu and click the "Add Index" button in the upper right corner.
http://localhost:8091/ui/index.html#!/fts_new/?indexType=fulltext-index&sourceType=couchbase
We write "eventsgeoindex" in the Name field.
We select "events" from the Bucket field.
Using the "+ insert child field" on the right side of the mapping named "default" under "Type Mappings", we add mappings as follows.
We add mapping to save the "Subject" information in the event to "eventsgeoindex".
We add mapping to save the "Address" information in the event to "eventsgeoindex".
We add mapping to save the "Date" information in the event to "eventsgeoindex".
We add mapping to search according to the "Location" information in the event.
The final situation will be as in the image below.
We create the index by clicking the "Create Index" button. When "Indexing progress" is 100%, it means that indexing has been finished.
http://localhost:8091/ui/index.html#!/fts_list?open=eventsgeoindex
2.3. Creating The Endpoint GetNearbyEvents
We add a class named "GetUpcomingEventsRequest" under the "Models" folder. This will be the request model of endpoint, which will return events near by our location.
namespace Couchbase.GeoSearchApp | |
{ | |
public class GetUpcomingEventsRequest | |
{ | |
public double Latitude { get; set; } | |
public double Longitude { get; set; } | |
public string Radius { get; set; } | |
} | |
} |
Likewise, we add a class named "GetUpcomingEventsResponse" under the "Models" file. This will be the endpoint's response model, which returns events that are near by our location.
namespace Couchbase.GeoSearchApp | |
{ | |
using System; | |
public class GetUpcomingEventsResponse | |
{ | |
public string Subject { get; set; } | |
public DateTimeOffset Date { get; set; } | |
public string Address { get; set; } | |
} | |
} |
We add a controller named "UpcomingEventsController".
In the line 30, we indicate that the search will be made on the basis of km.
In the line 40, we indicate the name of the "search index" that we will create in Couchbase.
namespace Couchbase.GeoSearchApp.Controllers | |
{ | |
using Couchbase.Core; | |
using Couchbase.Extensions.DependencyInjection; | |
using Couchbase.Search; | |
using Couchbase.Search.Queries.Geo; | |
using Microsoft.AspNetCore.Mvc; | |
using System; | |
using System.Collections.Generic; | |
using System.Threading.Tasks; | |
[Route("api/upcoming-events")] | |
[ApiController] | |
public class UpcomingEventsController : ControllerBase | |
{ | |
private readonly IBucket _bucket; | |
public UpcomingEventsController(IBucketProvider bucketProvider) | |
{ | |
_bucket = bucketProvider.GetBucket("events"); | |
} | |
[HttpGet] | |
public async Task<IActionResult> GetUpcomingEvents([FromQuery] GetUpcomingEventsRequest request) | |
{ | |
var query = new GeoDistanceQuery(); | |
query.Field("location"); | |
query.Latitude(request.Latitude); | |
query.Longitude(request.Longitude); | |
query.Distance($"{request.Radius}km"); | |
var searchParams = new SearchParams() | |
.Fields("*") | |
.Limit(10) | |
.Timeout(TimeSpan.FromMilliseconds(10000)); | |
var searchQuery = new SearchQuery | |
{ | |
Query = query, | |
Index = "eventsgeoindex", | |
SearchParams = searchParams | |
}; | |
var searchQueryResults = await _bucket.QueryAsync(searchQuery); | |
var result = new List<GetUpcomingEventsResponse>(); | |
foreach (var hit in searchQueryResults.Hits) | |
{ | |
result.Add(new GetUpcomingEventsResponse | |
{ | |
Subject = hit.Fields["subject"], | |
Address = hit.Fields["address"], | |
Date = hit.Fields["date"] | |
}); | |
} | |
return Ok(result); | |
} | |
} | |
} |
Now we can list events near by our location. Let's run the application and make requests from Postman as follows. By typing 1 and 2 to "Radius", you can see the events near 1 or 2km.
You can access the final version of the project from Github.
Good luck.
Top comments (1)
Couchbase connection information int the appsettings.json does not include in the article