I'm having trouble with Nested aggregations. Here is how I define my aggregations and the json equivalent I get:
var aggregations = new AggregationDictionary();
var nestedAgg = new AggregationContainer
{
Nested = new NestedAggregation("some_name1")
{
Path = "users",
Aggregations = new TermsAggregation("some_name2")
{
Field = "users.name.keyword",
Size = 100,
Order = new List<TermsOrder> { new TermsOrder() { Key = "_term", Order = SortOrder.Descending } }
}
};
aggregations[aggKey] = nestedAgg;
searchRequest.Aggregations = aggregations;
The above is translated to the following json. it only shows the path and no aggregations definition:
{
"aggs": {
"some_name1": {
"nested": {
"path": "users"
}
}
}
Using AggregationDictionary and AggregationContainer directly is a little awkward; You can do so like this
var aggregations = new AggregationDictionary();
var aggKey = "some_name1";
AggregationContainer nestedAgg = new NestedAggregation("some_name1")
{
Path = "users",
Aggregations = new TermsAggregation("some_name2")
{
Field = "users.name.keyword",
Size = 100,
Order = new List<TermsOrder>
{
new TermsOrder() { Key = "_term", Order = Nest.SortOrder.Descending }
}
}
};
aggregations[aggKey] = nestedAgg;
var searchRequest = new SearchRequest<Test>();
searchRequest.Aggregations = aggregations;
client.Search<Test>(searchRequest);
Here we use the implicit conversion from AggregationBase (the base class that aggregations derive from) to AggregationContainer to assign a NestedAggregation to a variable of type AggregationContainer.
This implicit conversion also sets the Aggregations and Meta properties on AggregationContainer, which is why your original attempt doesn't quote work correctly.
Related
If I was to use the high level model, I might try something like this:
public async void GetBooksData()
{
GetItemRequest request = new GetItemRequest
{
TableName = "Customer",
Key = new Dictionary<string, AttributeValue>
{
{"UserName", new AttributeValue{S="a"} },
{"BookNum", new AttributeValue { S = starts_with(queryTerm)} }
}
};
try
{
var response = await client.GetItemAsync(request);
if (response.HttpStatusCode == System.Net.HttpStatusCode.OK)
{
if (response.Item.Count > 0)
{
foreach (var item in response.Item)
{
MessageBox.Show("Value : \n" + item.Value.S);
}
}
}
}
catch (InternalServerErrorException iee)
{
MessageBox.Show(iee);
}
}
I need to use the method 'begins_with' for getting 2 items what UserName is 'a' and the BookNum are book_1 and book_2. This is possible in the high level interface in Java. As an example as to what can be done on the range key in Java:
public List<Comment> allForItemWithMinRating(String itemId, int minRating) {
Comment comment = new Comment();
comment.setItemId(itemId);
Condition condition = new Condition()
.withComparisonOperator(ComparisonOperator.GE)
.withAttributeValueList(
new AttributeValue()
.withN(Integer.toString(minRating)));
DynamoDBQueryExpression<Comment> queryExpression
= new DynamoDBQueryExpression<Comment>()
.withHashKeyValues(comment)
.withRangeKeyCondition(
"rating",
condition
)
.withScanIndexForward(false);
return mapper.query(Comment.class, queryExpression);
}
In the low level interface for C# you can achieve this as so:
var requestDynamodb = new QueryRequest
{
TableName = "GroupEdEntries",
KeyConditionExpression = "partition_key = :s_Id and begins_with(sort_key, :sort)",
ExpressionAttributeValues = new Dictionary<string, AttributeValue> {
{":s_Id", new AttributeValue { S = my_id }},
{":sort", new AttributeValue { S = sort_key_starts_with }}
},
ConsistentRead = true
};
var results = await client.QueryAsync(requestDynamodb);
where the keys are called partition_key and sort_key. However, this returns the results as attribute values, which then need to be converted into POCOs one property at a time. It requires using reflection and is made more complicated using converters. It seems strange that this fundamental functionality (as well as other functionality) isn't supported in the C# SDK.
I ended up using reflection to create the tables based on the attributes, when this is also supported by default in Java. Am I missing a high level API for C#?
It's a bit of a different syntax and I can't find it documented anywhere (other than in code comments), but this works for me:
string partition_key = "123";
string sort_key_starts_with = "#type"
List<object> queryVal = new List<object>();
queryVal.Add(sort_key_starts_with);
var myQuery = context.QueryAsync<GroupEdEntry>(partition_key, QueryOperator.BeginsWith, queryVal);
var queryResult = await myQuery.GetRemainingAsync();
I have a search method that queries Solr for event items. I need to modify it to only get events where the date has not already passed (i.e. Where(x => x.EventDate.Date >= DateTime.Now.Date), but I'm not sure how to add this because I'm not very familiar with Solr. Here's my search function:
public SearchQueryResults Search(string keywords, int page,int perPage, List<Guid> contentTypeFilters, List<Guid> otherFilters, ISortBuilder<SearchResultItem> sortBuilder)
{
var searchFilters = new List<IPredicateBuilder<SearchResultItem>>()
{
new IsSearchablePredicateBuilder()
};
if (contentTypeFilters.Any())
{
var contentTypePredicateBuilder = new ContentTypePredicateBuilder();
contentTypePredicateBuilder.ContentTypes = contentTypeFilters;
searchFilters.Add(contentTypePredicateBuilder);
}
if (otherFilters.Any())
{
var tagFilterBuilder = new TagsAndPredicateBuilder(otherFilters,_sitecoreContext);
searchFilters.Add(tagFilterBuilder);
}
if (string.IsNullOrWhiteSpace(keywords))
{
keywords = "";
}
SearchRequest searchRequest = new SearchRequest();
var queryParams = new Dictionary<string, string>() { };
queryParams.Add("q", keywords);
searchRequest.QueryParameters = queryParams;
searchRequest.SortBy = "";
searchRequest.SortOrder = "";
SearchQuery<SearchResultItem> queryArguments = new SearchQuery<SearchResultItem>();
queryArguments.FilterBuilders = searchFilters;
queryArguments.Page = page;
queryArguments.PerPage = perPage;
queryArguments.FacetsBuilder = new SearchFacetBuilder<SearchResultItem>();
queryArguments.SearchRequest = searchRequest;
queryArguments.IndexName = _indexName;
if (string.IsNullOrWhiteSpace(keywords))
{
queryArguments.QueryBuilders =new List<IPredicateBuilder<SearchResultItem>>();
}
else
{
queryArguments.QueryBuilders = new[] { new KeywordPredicateBuilder<SearchResultItem>(new[] { keywords }) };
}
queryArguments.SortBuilder = sortBuilder;
try
{
var results = _searchManager.GetResults<SearchResultItem>(queryArguments);
SearchQueryResults queryResults = new SearchQueryResults();
queryResults.ResultItems = results.Results;
queryResults.CurrentPage = page;
queryResults.TotalResults = Int32.Parse(results.TotalResults.ToString());
queryResults.TotalPages = (queryResults.TotalResults + perPage - 1) / perPage; ;
return queryResults;
}
catch (Exception exc)
{
Sitecore.Diagnostics.Log.Error("Error with FilteredSearch, could be a loss of connection to the SOLR server: " + exc.Message, this);
return null;
}
}
and here is how it's being called:
Results = _searchService.Search(searchTerm, CurrentPage - 1, 10, contentTypes, searchFilters,
new GenericSortBuilder<SearchResultItem>(q => q.OrderByDescending(r => r.SearchDate)));
How do I add in date filtering so that it only returns items where the date is in the future?
I would add filter query to the list of existing ones filtering the date field. On the documentation page, I was able to find information about fluent API, which could help here
Query.Field("date").From(DateTime.Now)
I'm not C# developer, that this code could have some mistakes, but I think the main idea is clear what needs to be done.
I am trying to set the value of object property which is of type List and initialise it by using a foreach to add the items to the list e.g.
var sessionPlanner = new SessionPlannerDTO()
{
Age = "",
NumberOfPlayers = session.numberOfPlayers.Value,
MedicalInformation = "",
PlayerNeeds = "",
SessionDate = session.daySessionDate.Value,
Location = session.Location.locationName,
PracticeView = new List<PracticeViewDTO>(foreach(var practice in session.Sessions){
new PracticeViewDTO(){AbilityLevel = practice.ActivityPlan.abilityLevel.Value,
ActivityUrl = practice.ActivityPlan.activityUrl,
EquipmentNeeds = practice.ActivityPlan.equipmentNeeds,
FacilityNeeds = practice.ActivityPlan.activityNeeds,
HealthAndSafety = practice.ActivityPlan.healthAndSafetyIssues,
SessionTitle = practice.ActivityPlan.activityName
};
})
};
PracticeView is what I am trying to achieve by making it a list without doing the below:
var practiceViewList = new List<PracticeViewDTO>();
foreach(var practice in session.Sessions)
{
var practiceX = new PracticeViewDTO()
{
AbilityLevel = practice.ActivityPlan.abilityLevel.Value,
ActivityUrl = practice.ActivityPlan.activityUrl
};
practiceViewList.Add(practiceX);
}
You can't use other code than assignments in object or collection initializers. So your foreach() there won't compile.
Use session.Sessions.Select() to map the source entities to your DTO, and ToList() to create a list of the result:
sessionPlanner = new SessionPlannerDTO
{
Age = "",
// ...
PracticeView = session.Sessions.Select(s =>
new PracticeViewDTO
{
AbilityLevel = s.ActivityPlan.abilityLevel.Value,
// ...
}).ToList()
};
You also may want to consider using AutoMapper, instead of hand-writing mapping code.
I have two lists which i want to get the different items from them
SearchElement[] criteria = new SearchElement[] {
new SearchElement
{
Comparison = "=",
FieldName = "CableProperty.ProjectId",
FieldValue = int.Parse(comboBoxSource.SelectedValue.ToString()),
LogicalOperator = "" }
};
sourceCables = client.GetCables(criteria, null, "Cores,CableProperty,CableProperty.CableApplication").ToList();
criteria = new SearchElement[] {
new SearchElement
{
Comparison = "=",
FieldName = "CableProperty.ProjectId",
FieldValue = int.Parse(comboBoxDestination.SelectedValue.ToString()),
LogicalOperator = "" }
};
destinationCables = client.GetCables(criteria, null, "Cores,CableProperty,CableProperty.CableApplication").ToList();
diffCables = sourceCables.Except(destinationCables, new CableComparer())
.ToList();
Now I have the different items in diffcable. Sometimes i want to set
diffCable.CableProperty.CableApplication = null;
but when i do that, all the navigation Porperty(CableApplication) in sourcelist is also set to null.
this is the code
if (destinationCableApplications.Contains(diffCable.CableProperty.CableApplication, new CableApplicationComparer()))
{
criteria = new SearchElement[] { new SearchElement { Comparison = "=", FieldName = "ProjectId", FieldValue = int.Parse(comboBoxDestination.SelectedValue.ToString()), LogicalOperator = "" }};
cableApplication = client.GetCableApplications(criteria, null, "").SingleOrDefault();
diffCable.CableProperty.CableApplication = null;
}
excatly in after this line
diffCable.CableProperty.CableApplication = null;
all the
sourcecables[0].CableProperty.CableApplication
sourcecables[1].CableProperty.CableApplication
.....
sourcecables[100].CableProperty.CableApplication
are set to null
what should i do to not lose the navigation property in sourcelist when i set null to navigation property in diffcable ?
easiest way is using MemoryStream..
Here is a sample,
[Serializable]
public class temp
{
public int a;
}
class Program
{
public static T DeepClone<T>(T a)
{
using (MemoryStream stream = new MemoryStream())
{
BinaryFormatter formatter = new BinaryFormatter();
formatter.Serialize(stream, a);
stream.Position = 0;
return (T)formatter.Deserialize(stream);
}
}
static void Main(string[] args)
{
List<temp> list1 = new List<temp>();
list1.Add(new temp { a = 1 });
list1.Add(new temp { a = 2 });
list1.Add(new temp { a = 3 });
List<temp> list2 = DeepClone<List<temp>>(list1);
list1[1].a = 4;
Console.WriteLine(list2[1].a);
Console.ReadKey();
}
}
Note: class must be Serializable.
This will work for all value and reference types.
You are doing a copy by reference without realising it. Look into Cloning your objects or creating new lists.
List<int> newCopyList = new List<int>(originalList);
I'm searching a sorted dictionary with a key of type datetime and values as list of objects. What I need to find is the latest value(based on a property on the object) for each object in the dictionary. My object has 3 properties : a name, a value and a date when it was created. My dictionary is sorted by latest date in descending order.
I have got this working somehow, but I'm sure there is a shortcut for this using LINQ. Please note that I'm using .NET 3.5. Could you please help? Please dont get put off by the huge amount code below as I have added it for clarity and i'm only looking for a linq query to query inside a list of list objects.
Code below:
public void Should_link_recent_data_together()
{
var data = TimeSeriesDataFactoryEx.GetData();
var allAttributes = new List<string>()
{
TimeSeriesConstants.TOTAL_COST_CODE,
TimeSeriesConstants.TOTAL_VALUE_CODE,
TimeSeriesConstants.SOURCE_CODE
};
var latestList = new List<TimeSeries>();
var allValues = data.Values.ToList();
#region HOW DO I DO THIS USING LINQ?
bool found = false;
foreach (var attribute in allAttributes)
{
found = false;
foreach (var tsData in allValues)
{
foreach (var ts in tsData)
{
if (ts.MetricName == attribute && !string.IsNullOrEmpty(ts.MetricValue))
{
latestList.Add(ts);
found = true;
break;
}
}
if (found)
break;
}
}
#endregion
Assert.IsTrue(latestList.Count == 3);
Assert.IsTrue(latestList.Where(x => x.MetricName == TimeSeriesConstants.TOTAL_COST_CODE).First().MetricValue == "1");
Assert.IsTrue(latestList.Where(x => x.MetricName == TimeSeriesConstants.TOTAL_VALUE_CODE).First().MetricValue == "2");
Assert.IsTrue(latestList.Where(x => x.MetricName == TimeSeriesConstants.SOURCE_CODE).First().MetricValue == "gp");
Assert.IsTrue(latestList.Where(x => x.MetricName == TimeSeriesConstants.SOURCE_CODE).First().Quarter == DateTime.Today.AddMonths(-3));
}
internal class TimeSeriesDataFactoryEx
{
public static SortedDictionary<DateTime?,List<TimeSeries>> GetData()
{
return new SortedDictionary<DateTime?, List<TimeSeries>>(new DateComparer())
{
{
DateTime.Today, new List<TimeSeries>()
{
new TimeSeries()
{
Quarter = DateTime.Today,
MetricValue = "1",
MetricName = TimeSeriesConstants.TOTAL_COST_CODE
},
new TimeSeries()
{
Quarter = DateTime.Today,
MetricValue = "2",
MetricName = TimeSeriesConstants.TOTAL_VALUE_CODE
},
new TimeSeries()
{
Quarter = DateTime.Today,
MetricValue = "",
MetricName = TimeSeriesConstants.SOURCE_CODE
}
}
},
{
DateTime.Today.AddMonths(-3), new List<TimeSeries>()
{
new TimeSeries()
{
Quarter = DateTime.Today.AddMonths(-3),
MetricValue = "3",
MetricName = TimeSeriesConstants.TOTAL_COST_CODE
},
new TimeSeries()
{
Quarter = DateTime.Today.AddMonths(-3),
MetricValue = "4",
MetricName = TimeSeriesConstants.TOTAL_VALUE_CODE
},
new TimeSeries()
{
Quarter = DateTime.Today.AddMonths(-3),
MetricValue = "gp",
MetricName =TimeSeriesConstants.SOURCE_CODE
}
}
}
};
}
}
So, assuming I understand your question right, say you have a dictionary like so:
{ Key = "1/1/1900", Value = List Of Objects, of which each has a DateTimeProperty }
...
{ Key = "1/4/1900", Value = List Of Objects, of which each has a DateTimeProperty }
And you are looking to find a set of objects from your dictionary, where it's the latest by time of each key, then you can do this pretty simply with linq:
var latestItems = data.SelectMany(kvp =>
kvp.Value.OrderByDescending(value => value.Quarter).Take(1)
);
This query finds the most recent object in each bucket and then returns that as a single set (not an enumerable of enumerables). You can change the selector inside the SelectMany to find elements in each set as much as you want, as long as you return an IEnumerable from that callback.