Posted on 09/01/2020 00:49:30
Hi Nicolai,
It did, thanks. Scott Sargent was also key helping debug this. The hardest thing was that Dynamicweb is generating a collection of objects that "happen to be" a Dictionary<string, object>. We also had to cast each object to a dictionary to work with it. Once we did that (and other normal debuging headaches) we got it to work.
I wonder why isn't Dynamicweb generating a collection of dictionaries in the first place? we'd avoid all of those casts.
Anyway, now we can calculate distances based on a provided lat-lon and then return only the closest ones back. In case it helps anyone with either the AfterQuery or this logic, here's the code
using System;
using System.Web;
using System.Collections.Generic;
using System.Linq;
namespace Dna.Winnebago.IndexBuilderExtender
{
[Dynamicweb.Extensibility.Notifications.Subscribe(Dynamicweb.Indexing.Notifications.Query.AfterQuery)]
public class AfterQuery : Dynamicweb.Extensibility.Notifications.NotificationSubscriber
{
public override void OnNotify(string notification, Dynamicweb.Extensibility.Notifications.NotificationArgs args)
{
if (!(args is Dynamicweb.Indexing.Notifications.Query.AfterQueryArgs afterQueryArgs)
|| afterQueryArgs.Query.Name != Constants.QueryPublisher.QueryName
|| !HasLatAndLong())
{
return;
}
CalculateDistance(afterQueryArgs.Result.QueryResult);
afterQueryArgs.Result.QueryResult = Sort(afterQueryArgs.Result.QueryResult, Constants.QueryPublisher.DistanceToCenter + " asc");
afterQueryArgs.Result = FilterResults(afterQueryArgs.Result);
}
private bool HasLatAndLong()
{
var latitude = HttpContext.Current.Request[Constants.QueryString.Latitude];
var longitude = HttpContext.Current.Request[Constants.QueryString.Longitude];
return !string.IsNullOrEmpty(latitude) && !string.IsNullOrEmpty(longitude);
}
private double GetCenterLatOrLong(string queryStringParameter)
{
var parameter = HttpContext.Current.Request[queryStringParameter];
if (double.TryParse(parameter, out var degrees))
{
return degrees;
}
return 0;
}
private void CalculateDistance(IEnumerable<object> dealers)
{
var centerPointLat = GetCenterLatOrLong(Constants.QueryString.Latitude);
var centerPointLon = GetCenterLatOrLong(Constants.QueryString.Longitude);
foreach (var obj in dealers)
{
var dealer = (Dictionary<string, object>) obj;
double distanceBetweenPlaces = 1000000000;
if (HasLatAndLong(dealer))
{
var docLat = double.Parse(dealer[Constants.User.Latitude].ToString());
var docLon = double.Parse(dealer[Constants.User.Longitude].ToString());
distanceBetweenPlaces = Helpers.DistanceBetweenPlaces(centerPointLon, centerPointLat, docLon, docLat);
}
SetDistance(dealer, distanceBetweenPlaces);
}
}
private bool HasLatAndLong(Dictionary<string, object> doc)
{
if (doc == null) return false;
var latitude = doc.ContainsKey(Constants.User.Latitude) ? doc[Constants.User.Latitude]?.ToString() : "";
var longitude = doc.ContainsKey(Constants.User.Longitude) ? doc[Constants.User.Longitude]?.ToString() : "";
return !string.IsNullOrEmpty(latitude) && !string.IsNullOrEmpty(longitude) && latitude != "0" && longitude != "0";
}
private void SetDistance(Dictionary<string, object> dealer, double distanceBetweenPlaces)
{
if (!dealer.ContainsKey(Constants.QueryPublisher.DistanceToCenter))
{
dealer.Add(Constants.QueryPublisher.DistanceToCenter, distanceBetweenPlaces);
}
else
{
dealer[Constants.QueryPublisher.DistanceToCenter] = distanceBetweenPlaces;
}
}
private static IEnumerable<object> Sort(IEnumerable<object> data, string orderByString)
{
var dealers = new List<Dictionary<string, object>>();
data.ToList().ForEach(o => dealers.Add(o as Dictionary<string, object>));
var orderBy = orderByString
.Split(',')
.Select(s => s.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries))
.Select(a => new { Field = a[0], Descending = "desc".Equals(a[1], StringComparison.InvariantCultureIgnoreCase) })
.ToList();
if (orderBy.Count == 0)
return data;
// First one is OrderBy or OrderByDescending.
IOrderedEnumerable<Dictionary<string, object>> ordered = orderBy[0].Descending ? dealers.OrderByDescending(d => d[orderBy[0].Field]) : dealers.OrderBy(d => d[orderBy[0].Field]);
for (int i = 1; i < orderBy.Count; i++)
{
// Rest are ThenBy or ThenByDescending.
var orderClause = orderBy[i];
ordered = orderBy[i].Descending ? ordered.ThenByDescending(d => d[orderClause.Field]) : ordered.ThenBy(d => d[orderClause.Field]);
}
return ordered;
}
private Dynamicweb.Indexing.Querying.IQueryResult FilterResults(Dynamicweb.Indexing.Querying.IQueryResult dealers)
{
var maxResults = GetMaxResultsParameter() != 0 ? GetMaxResultsParameter() : 3;
var filteredResults = dealers;
filteredResults.QueryResult = filteredResults.QueryResult.Take(maxResults);
filteredResults.TotalCount = filteredResults.QueryResult.Count();
filteredResults.Count = filteredResults.QueryResult.Count();
return filteredResults;
}
private int GetMaxResultsParameter()
{
var maxResultsParameter = HttpContext.Current.Request["MaxResults"];
if (string.IsNullOrEmpty(maxResultsParameter))
{
maxResultsParameter = "0";
}
return int.Parse(maxResultsParameter);
}
}
}
Best Regards,
Nuno Aguiar