Elastic / Nest (C#) - Get max Id in index - c#

I have an entity stored inside an Elastic Index, one of his fields is an Id (int).
I'm currently using this code to retrieve the data:
var searchRequest = new SearchRequest<MyEntity>(indexName)
{
Size = 1,
Query = new MatchAllQuery(),
Sort = new List<ISort>()
{
new FieldSort(){ Field = "_id", Order = SortOrder.Descending }
}
};
var result = await _elasticClient.SearchAsync<MyEntity>(searchRequest);
var highestId = result.Documents.First().Id;
This code does not return the max Id but it returns the id "999999".
What I think its happening is that "_id" in search request it's not the Id inside my entity.
What is the correct way to query that value instead?
Edit:
I tried of course using "id" (or Id) in the code up above but I get an excpetion
Elasticsearch.Net.UnexpectedElasticsearchClientException : expected:'true | false', actual:'"true"', at offset:639
Also I tried this but I get an id that its even lower that the previous one:
var response = await _elasticClient.SearchAsync<MyEntity>(s => s
.Index(indexName)
.Size(1)
.Aggregations(a =>
a.Max("max_id", x => x.Field("id"))
)

if you use id your entity try this:
GET my-index-000001/_search
{
"size": 0,
"aggs": {
"max_id": {
"max": {
"field": "id"
}
}
}
}

In the end here's the solution:
After the response from #rabbitbr I was able to get this request:
var response = await _elasticClient.SearchAsync<MyEntity>(s => s
.Index(indexName)
.Take(1)
.Aggregations(aggr =>
aggr.Max("get_max_id", max =>
max.Field(field => field.Id)
)
)
);
var highestId = result.Documents.First().Id;
Here my error was NOT the query but how I collected the result: the correct way to get the value of "highestId" is to get from the response the field "Aggregations", then using .Max(aggregationName)
var aggregationName = "get_max_id";
var response = await _elasticClient.SearchAsync<MyEntity>(s => s
.Index(indexName)
.Take(0)
.Aggregations(aggr =>
aggr.Max(aggregationName , max =>
max.Field(field => field.Id)
)
)
);
var highestId = response.Aggregations.Max(aggregationName).Value;

Related

ElasticSearch NEST Upsert with set on insert

I have the following code to upsert documents to my index, which works well:
var dtos = new PlayerDto[]
{
new PlayerDto
{
Id = "1",
AccountId = "1",
Name = "test"
}
};
var response = await _elastic.BulkAsync(b => b
.Index(indexName)
.UpdateMany(dtos, (bu, d) => bu.Doc(d).DocAsUpsert(true))
);
However, I don't want to override the Name field every time I upsert. Can I make it so the Name field is only set when the document is inserted, not updated? Or alternatively, set Name only if the existing Name is null?
Sure, just make field of the upserting document NULL. For example like this:
public class PlayerDto {
public PlayerDto(PlayerDto model) {
Id = model.Id,
AccountId = model.AccountId,
Name = null
}
}
var response = await _elastic.BulkAsync(b => b
.Index(indexName)
.UpdateMany(dtos, (bu, d) => bu.Doc(new PlayerDto(d)).Upsert(d)));

Use List of data from one web api to another api

I have one api with name abc-api and in this I am getting records using following function. Now I want to use this data in another api, below is code I have tried..but can't use this data in that api..
public async Task<ICollection<CarrierCompilanceDocumentViewModel>> RefreshComplianceDocumentNotification(Guid tenantId, Guid countryId)
{
DateTime now = DateTime.UtcNow;
var now1 = DateTime.UtcNow;
var expiriesDays = new List<int> { 1, 7, 14 };
var expiriesDates = expiriesDays.Select(x => now1.AddDays(x).Date).ToList();
var carrierAdminUserEmails = _dbContext.CarrierUsers.IgnoreQueryFilters()
.Where(x => x.IsAdmin)
.Where(x => !x.IsDeleted && x.TenantId == tenantId && x.TenantCountryId == countryId)
.Where(x => x.Carrier.ComplianceExpiryDate != null)
.Select( x => new { x.Email, x.Carrier.ComplianceExpiryDate })
.Distinct();
return (ICollection<CarrierCompilanceDocumentViewModel>)carrierAdminUserEmails; }
Now I am getting in this carrierAdminUserEmails 3 values with Email and ComplianceExpiryDate.
Now I am calling this function from one another web-api and I want to use this values there..but I don't know how to use that..below is code I have done till now in that another web-api.
var client = _clientFactory.CreateClient("carrier");
var request = HttpHelper.GetRequestMessageApiKey(_config, HttpMethod.Post,
$"{_carrierHost}/api/cms/carrier-company/RefreshComplianceDocumentNotification?tenantId={tenantId}&countryId={countryId}");
var response = await HttpHelper.GetResponseMessage(client, request);
var result = response.Content.ReadAsStringAsync().Result;
But not getting that 3 values in this web-api, any idea how to use that 3 values in this api.

LINQ Data Sorting

I am trying to fill select tag options from JQuery ajax call. I am using Asp.Net Core 2.1 Razor Pages, and PostgreSQL as DB.
Here is my Server side LINQ code
[HttpGet]
public ActionResult TypeofAccounts()
{
var result = (from N in _POSContext.TypeOfAccounts
select new { label = N.AccountType, id = N.AccountType });
return Json(result);
}
It works fine. Now, I want to sort those results from LINQ so I tried following ways but it always encounters Npgsql Exception "column \"label\" does not exist"
var result = (from N in _POSContext.TypeOfAccounts.OrderBy(x=>x.AccountType)
select new { label = N.AccountType, id = N.AccountType });
var result = (from N in _POSContext.TypeOfAccounts
select new { label = N.AccountType, id = N.AccountType }).OrderBy(x => x.label);
var result = (from N in _POSContext.TypeOfAccounts.OrderBy(x => x.AccountType)
where N.AccountType != null
select new { label = N.AccountType, id = N.AccountType });
I could see coloumn is missing in generated sql.
{SELECT x."AccountType" AS id
FROM "TypeOfAccounts" AS x
WHERE x."AccountType" IS NOT NULL
ORDER BY label}
You need to invoke the query from the database using ToList method, then selecting your object, like this:
var result = _POSContext.TypeOfAccounts
.Where(x => x.AccountType != null)
.OrderBy(x => x.AccountType)
.ToList()
.Select(x =>
new
{
label = x.AccountType,
id = x.AccountType
}
);
You can try this
var result = _POSContext.TypeOfAccounts
.Where(x => x.AccountType != null)
.OrderBy(x => x.AccountType)
.ToList()
.Select(x =>
new
{
label = x.AccountType,
id = x.AccountType
}
);

Counting nested Navigation table rows with LINQ

I am very new to c# and LINQ, now I need to do some aggregation on the navigation tables nested one after the other, the result was generated as below:
[{
"ForumMain":"General Forum",
"Forums": [{
"Title":"My First Forum",
"TopicCount":4,
"PostCount":[2,0,1,0]
},
{
"Title":"My Second Forum",
"TopicCount":0,
"PostCount":[]
}]
}]
I wanted PostCount also be the sum, but it is giving debug null error when I try to sum PostCount, please see my linq query below:
var data = ForumCategories.Select(f => new
{
ForumMain = f.CategoryName,
Forums = f.Fora.Select(t => new
{
Title = t.ForumName,
TopicCount = t.Topics.Count,
PostCount = t.Topics
.Select(m => m.ForumPosts.Count == null ? 0 : m.ForumPosts.Count)
})
});
From what I understand what you want under PostCount to have the total number of post you have for all the topics in that Forum. Right?
If so:
var data = db.ForumCategories.Select(f => new
{
ForumMain = f.CategoryName,
Forums = f.Fora.Select(t => new
{
Title = t.ForumName,
TopicCount = t.Topics.Count,
PostCount = t.Topics.SelectMany(x => x.ForumPosts).Count()
})
});

Nest aggregation not working correctly

I have a use case where I need to do aggregation on multiple columns using C#.
I am using NEST libraries for this and I am facing the following issue
Query C# :
var searchRequest = new SearchRequest
{
SearchType = SearchType.Count,
Filter = filter,
Aggregations = new Dictionary<string, IAggregationContainer>
{
{ "a", new AggregationContainer
{
ExtendedStats = new ExtendedStatsAggregator()
{
Field = "a"
}
}
},
{ "b", new AggregationContainer
{
ExtendedStats = new ExtendedStatsAggregator()
{
Field = "b"
}
}
}
}
};
When I receive response from NEST, however I am getting only result for one aggregation. I am looking at SearchResult.Agg dictionary but it has only one entry for one aggregation field instead of two.
Let me know if I am missing soemthing or is it some issue with NEST libraries
if you are using term aggregation then you need to use aggregation with filter.
var qryRes1 = client.Search<object>(x => x
.Aggregations(ag => ag
.Filter("filter", (flt => flt
.Filter(f =>
{
FilterContainer filter = null;
filter &= f.Query(qr => qr.Term(wl => wl.OnField("a").Value("the value you need to filter for field a")));
return filter;
})
.Aggregations(agr => agr
.Terms("b", tr =>
{
TermsAggregationDescriptor<object> trmAggDescriptor = new TermsAggregationDescriptor<object>();
trmAggDescriptor.Field("b");
return trmAggDescriptor;
}))))
));
var terms = qryRes1.Aggs.Filter("filter").Terms("b");

Categories