Skip to content

Commit

Permalink
Merge pull request #168 from AirQualityControl/feature/implement-get-…
Browse files Browse the repository at this point in the history
…airpollution-by-geolocation

implement feature
  • Loading branch information
ArturLavrov authored Dec 29, 2023
2 parents fabaeb4 + 61be816 commit 97d4b76
Show file tree
Hide file tree
Showing 6 changed files with 102 additions and 20 deletions.
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Linq;
using System.Threading.Tasks;
using AirSnitch.Api.Controllers.AirQualityIndexController.ViewModel;
using AirSnitch.Api.Rest;
Expand Down Expand Up @@ -42,16 +43,22 @@ public AirQualityIndexController(
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<IActionResult> GetIndexValue([FromQuery]AirQualityIndexRequestParams requestParams)
{
//TODO:https://github.com/AirQualityControl/server/issues/93
var nearestStation =
await _monitoringStationRepository.GetNearestStation(requestParams.Geolocation, requestParams.Radius);
var nearestStations =
await _monitoringStationRepository.GetNearestStations(requestParams.Geolocation, numberOfStations:10);

if (nearestStation.IsEmpty)
if (!nearestStations.Any())
{
return NotFound();
}

var airPollution = nearestStation.GetAirPollution();

var activeStation = nearestStations.FirstOrDefault(station => station.HasActualData());

if (activeStation == null)
{
return NotFound();
}

var airPollution = activeStation.GetAirPollution();

var usaAqi = new UsaAirQualityIndex();

Expand All @@ -61,12 +68,11 @@ public async Task<IActionResult> GetIndexValue([FromQuery]AirQualityIndexRequest
index: usaAqi,
indexValue:indexValue,
Request);


//aqiViewModel.SetMeasurementDateTime(airPollution.GetMeasurementsDateTime());
aqiViewModel.SetMeasurementDateTime(airPollution.GetMeasurementsDateTime());

aqiViewModel.SetStationId(activeStation.Id);

aqiViewModel.SetStationId("5480d666-cd1e-45ff-9e63-f283592c72e2");

return new RestApiResult(
new RestResponseBody(
Request,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
using AirSnitch.Domain.Models;
using AirSnitch.Infrastructure.Abstract.Persistence.Repositories;
using Microsoft.AspNetCore.Mvc;

namespace AirSnitch.Api.Controllers.AirQualityIndexController
Expand All @@ -11,10 +10,7 @@ public class AirQualityIndexRequestParams

[FromQuery(Name = "lat")]
public double LatitudeValue { get; set; }

[FromQuery(Name = "radius")]
public int Radius { get; set; }


internal GeoCoordinates Geolocation => new() {Latitude = LatitudeValue, Longitude = LongitudeValue};
}
}
7 changes: 7 additions & 0 deletions src/AirSnitch.Domain/Models/MonitoringStation.cs
Original file line number Diff line number Diff line change
Expand Up @@ -111,5 +111,12 @@ private string GenerateId()
{
return Guid.NewGuid().ToString();
}

public bool HasActualData()
{
var measurementsDateInUtc = GetAirPollution().GetMeasurementsDateTime();

return DateTime.UtcNow - measurementsDateInUtc <= TimeSpan.FromHours(2);
}
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System.Collections.Generic;
using System.Threading.Tasks;
using AirSnitch.Domain.Models;
using AirSnitch.Infrastructure.Abstract.Persistence.Query;
Expand Down Expand Up @@ -26,7 +27,7 @@ public interface IMonitoringStationRepository
///
/// </summary>
/// <returns></returns>
Task<MonitoringStation> GetNearestStation(GeoCoordinates geoCoordinates, int radius = default);
Task<MonitoringStation> GetNearestStation(GeoCoordinates geoCoordinates, int radius = 5, int numberOfStations = 10);

/// <summary>
/// Search station by provider station name
Expand All @@ -35,6 +36,15 @@ public interface IMonitoringStationRepository
/// <returns></returns>
Task<MonitoringStation> FindByProviderNameAsync(string providerStationName);

/// <summary>
/// Returns n nearest stations by geolocation
/// </summary>
/// <param name="geoCoordinates"></param>
/// <param name="numberOfStations"></param>
/// <returns></returns>
Task<ICollection<MonitoringStation>> GetNearestStations(GeoCoordinates geoCoordinates,
int numberOfStations = 10);

Task AddAsync(MonitoringStation monitoringStation);
Task UpdateAsync(MonitoringStation monitoringStation);
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading.Tasks;
using AirSnitch.Domain.Models;
Expand All @@ -9,15 +11,17 @@
using AirSnitch.Infrastructure.Persistence.Repositories.Common;
using AirSnitch.Infrastructure.Persistence.StorageModels;
using MongoDB.Bson;
using MongoDB.Driver;

namespace AirSnitch.Infrastructure.Persistence.Repositories
{
public class MonitoringStationRepository : IMonitoringStationRepository
{
private readonly IGenericRepository<MonitoringStationStorageModel> _genericRepository;

private readonly MongoDbClient _client;
public MonitoringStationRepository(MongoDbClient client)
{
_client = client;
_genericRepository = new MongoDbGenericRepository<MonitoringStationStorageModel>(client, "airMonitoringStation");
}

Expand Down Expand Up @@ -91,10 +95,30 @@ public async Task<MonitoringStation> FindByProviderNameAsync(string providerStat
return MonitoringStation.Empty;
}

public Task<MonitoringStation> GetNearestStation(GeoCoordinates geoCoordinates, int radius = default)
public async Task<MonitoringStation> GetNearestStation(GeoCoordinates geoCoordinates, int radius = default, int numberOfStations = 10)
{
throw new NotImplementedException();
}

public async Task<ICollection<MonitoringStation>> GetNearestStations(GeoCoordinates geoCoordinates,
int numberOfStations = 10)
{
var monitoringStation = new MonitoringStation();
return Task.FromResult(monitoringStation);
var monitoringStations = new List<MonitoringStation>(numberOfStations);

var pipeline = NearestStationsAggregationPipeline.Create(geoCoordinates, numberOfStations);

var collection = _client.Db.GetCollection<MonitoringStationStorageModel>("airMonitoringStation");

var cursor = collection.Aggregate<MonitoringStationStorageModel>(pipeline);

Action<MonitoringStationStorageModel> cursorAction = st =>
{
monitoringStations.Add(st.MapToDomainModel());
};

await cursor.ForEachAsync(cursorAction);

return monitoringStations;
}

public async Task AddAsync(MonitoringStation monitoringStation)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
using System.Collections.Generic;
using AirSnitch.Domain.Models;
using MongoDB.Bson;

namespace AirSnitch.Infrastructure.Persistence.Repositories;

internal static class NearestStationsAggregationPipeline
{
public static List<BsonDocument> Create(GeoCoordinates geoLocation, int numberOfNearestStation)
{
int numOfPipelineStages = 2;

var geoNearOptions = new BsonDocument
{
{
"near", new BsonDocument
{
{"type", "Point"},
{"coordinates", new BsonArray {geoLocation.Longitude, geoLocation.Latitude}},
}
},
{"key", "geoLocation"},
{"distanceField", "dist.calculated"},
};

var limitOptions = new BsonDocument()
{
{"$limit", numberOfNearestStation}
};

var pipeline = new List<BsonDocument>(numOfPipelineStages)
{
new BsonDocument {{"$geoNear", geoNearOptions}},
limitOptions
};

return pipeline;
}
}

0 comments on commit 97d4b76

Please sign in to comment.