Dynamic Bool Query for NEST (ElasticSearch) - elasticsearch

Good day:
I'm trying to achieve a dynamic Bool Query. Example...
QueryContainer addressQuery = null;
QueryContainer typeQuery = null;
BoolQueryDescriptor <Facility> boolQuery = new BoolQueryDescriptor<Facility>();
QueryContainerDescriptor<Facility> sh = new QueryContainerDescriptor<Facility>();
SearchDescriptor<Facility> mainSh = new SearchDescriptor<Facility>();
if (search.searchTerm != null)
{
addressQuery = sh.Term(f => f.Address, search.searchTerm) ||
sh.Match(m => m.Field(f => f.Address).Query(search.searchTerm) ) ||
sh.Term(f => f.ZipCode, search.searchTerm) ||
sh.Match(m => m.Field(f => f.State).Query(search.searchTerm));
boolQuery = boolQuery.Should(b => addressQuery);
}
if (search.type != null) {
typeQuery = sh.Term(f => f.Types.First(), search.type);
boolQuery = boolQuery.Must(b => typeQuery && addressQuery);
}
if (boolQuery != null)
{
mainSh = mainSh.Query(q => q.Bool(b => boolQuery));
request = await this._elasticClient.SearchAsync<Facility>(s => mainSh.Size(search.size));
}
This query is turning into a OR between AddressQuery and TypeQuery however, I'd like to achieve an And condition between both query. Effectively making the query dynamic. Is this possible? Example: dynamic addressQuery && typeQuery.
Thanks.

Fire it out..you can && or || query containers...sorter like:
queryContainer1=queryContainer1 && queryContainer2
Then .bool(b => b(queryContainer1)).

Related

ElasticSearch NEST ObjectInitializer syntax to fluent syntax translation not working

Given this ObjectInitializer NEST query
var mustClauses = new List<QueryContainer>
{
new QueryStringQuery
{
Query = queryFilter.Query,
Lenient = true
},
new MatchQuery
{
Field = new Field("status"),
Query = queryFilter.Status,
Lenient = true,
Operator = Operator.And
},
new DateRangeQuery
{
Field = new Field("timeSent"),
LessThanOrEqualTo = now,
GreaterThanOrEqualTo = GetDateTimeFor(queryFilter.TimeCriteria, now)
}
};
return client.SearchAsync<Ingestion.Entities.ElasticSearch.MessageData>(sd => sd.Query(q => q.Bool(b => b.Must(mustClauses.ToArray())))
.Sort(x => x.Descending(b => b.TimeSent))
.From(from)
.Size(pageSize));
which works, and outputs the following query to my Visual Studio Output window:
{"from":0,"query":{"bool":{"must":[{"match":{"status":{"lenient":true,"operator":"and","query":"Success"}}},{"range":{"timeSent":{"gte":"2021-12-14T03:39:26.5126419Z","lte":"2021-12-21T03:39:26.5126419Z"}}}]}},"size":20,"sort":[{"timeSent":{"order":"desc"}}]}
I am trying to convert it to fluent query syntax like this:
return client.SearchAsync<Ingestion.Entities.ElasticSearch.MessageData>(sd => sd.Query(q => q.Bool(b => b.Must(
mu => mu
.QueryString(qs => qs
.Query(queryFilter.Query)
.Lenient(true)),
mu =>
{
if (string.IsNullOrEmpty(queryFilter.Status))
return null;
return mu
.Match(ma => ma.Field(f => f.Status == queryFilter.Status)
.Lenient(true)
.Operator(Operator.And));
},
mu =>
{
if (queryFilter.TimeCriteria == TimeCriteria.All)
return null;
return mu.DateRange(dr => dr
.Field(f => f.TimeSent)
.LessThanOrEquals(now)
.GreaterThanOrEquals(GetDateTimeFor(queryFilter.TimeCriteria, now)));
})))
.Sort(x => x.Descending(b => b.TimeSent))
.From(from)
.Size(pageSize));
and it's not working. When I run this query, the Match query on that Status field does not appear in the NEST output.
Any guidance/help would be appreciated.
The status lambda expression should be
mu =>
{
if (string.IsNullOrEmpty(queryFilter.Status))
return null;
return mu
.Match(ma => ma.Field(f => f.Status)
.Query(queryFilter.Status)
.Lenient(true)
.Operator(Operator.And));
},

LINQ: Cannot get more than two Where clauses to work

I cannot get the following to work properly. I want to search my database using more than 2 conditions where it will be possible to search only on one, two or all three, thus narrowing the search. At the moment, I can only get it to work with one condition at a time, and it only evaluates the first condition when having more than 3.
How can I Include more than 2 conditions? I have tried several proposed solutions from other sources, that uses if statements and where clauses, but so far none of them have worked.
This is my controller
public IActionResult Index(string searchString, int searchProject, string searchTitel)
{
var Projektdokumenter = from p in _context.ProjekterDokutypeDokuundertype
.Include(p => p.Dokumenttype)
.Include(p => p.Dokuundertype)
.Include(p => p.Forfatter)
.Include(p => p.P)
.Include(p => p.Sprog)
select p;
if (!String.IsNullOrEmpty(searchString) ^ searchProject != null ^ !String.IsNullOrEmpty(searchTitel))
{
if (!String.IsNullOrEmpty(searchString))
{
var c = Projektdokumenter.Where(p => p.Forfatter.Initialer.Contains(searchString)).ToList();
return View(c);
}
{
if (searchProject != 0)
{
var d = Projektdokumenter.Where(p => p.P.ProjektId.Equals(searchProject)).ToList();
return View(d);
}
{
if(!String.IsNullOrEmpty(searchTitel))
{
var f = Projektdokumenter.Where(p => p.Titel.Contains(searchTitel)).ToList();
return View(f);
}
}
}
}
var e = Projektdokumenter.Where(c.Contains(searchString) && p.P.ProjektId.Equals(searchProject) && p.Titel.Contains(searchTitel)).ToList();
return View(e);
}
IQueryable can be combined, so just write in native way:
{
var query = _context.ProjekterDokutypeDokuundertype
.Include(p => p.Dokumenttype)
.Include(p => p.Dokuundertype)
.Include(p => p.Forfatter)
.Include(p => p.P)
.Include(p => p.Sprog)
.AsQueryable();
if (!string.IsNullOrEmpty(searchString))
{
query = query.Where(p => p.Forfatter.Initialer.Contains(searchString));
}
if (searchProject != 0)
{
query = query.Where(p => p.P.ProjektId == searchProject);
}
if (!string.IsNullOrEmpty(searchTitel))
{
query = query.Where(p => p.Titel.Contains(searchTitel))
}
return View(query.ToList());
}

How do I exclude certain parts of a .Include on a condition?

We are trying to exclude certain data from our queries based on a condition, but we can't seem to get it right. Our current code looks like this:
var PullData = _context.RequestInformation.Include(x => x.RequestMinistry)
.Include(x => x.RequestApps)
.ThenInclude(x => x.RequestAppDataChoices)
.Where(x => x.RequestStatus != "Cancelled With Reason")
.Where(y => y.RequestApps.SelectMany(x => x.RequestAppDataChoices)
.Where(s => s.AppDataChoiceDl.Contains(groupName))
.Where(a => a.RequestApps.AppProvisioningCompleteTime != null)
.Where(aa => aa.RequestApps.AppTeamCompleteTime == null)
.Where(ab => !ab.RequestApps.AppStatus.Contains("Rejected")).Any());
This is fine as long as we are trying to pull all of the "RequestApps" with each set of "RequestInformation", however if we want to pull just specific applications based on conditions, it doesn't work. We want to only show the request apps based on the the conditions above (The appdatachoicedl contains "groupname", the completetime != null while the other completetime IS null, and that the status is not rejected), but instead, we are getting all the request information that matches those conditions.
I tried something like this, but it still doesn't quite give me the results I need. It gives me random blank results as well:
var PullDataV2 = from reqInfo in _context.RequestInformation
join RA in _context.RequestApps on reqInfo.ReqNum equals RA.ReqNum
join RADC in _context.RequestAppDataChoices on RA.PkId equals RADC.RequestAppsId
where RADC.AppDataChoiceDl == groupName
select new RequestInformation()
{
ProvisioningCompleteTime = reqInfo.ProvisioningCompleteTime,
RequestMinistry = reqInfo.RequestMinistry,
RequestApps = reqInfo.RequestApps,
UserFirstName = reqInfo.UserFirstName,
UserLastName = reqInfo.UserLastName,
SubmitterFirstName = reqInfo.SubmitterFirstName,
SubmitterLastName = reqInfo.SubmitterLastName,
RequestStatus = reqInfo.RequestStatus
};
I hope I'm making sense here - I only want the requestapps based on the conditions, not all the request information that is those conditions. RequestApps is a part of the RequestInformation class.
Edit:
Piggybacking off of Roberts comments, I modified his code to look like this, but I am struggling with the last line - I need to be able to make sure that "AppDataChoiceDL" which is a member of RequestAppDataChoices (which is a member of RequestApps) is equal to groupName
var PullData = _context.RequestInformation.Include(x => x.RequestMinistry)
.Include(x => x.RequestApps)
.ThenInclude(x => x.RequestAppDataChoices)
.Where(x => x.RequestStatus != "Cancelled With Reason")
.Where(x => x.RequestApps.SelectMany(app => app.RequestAppDataChoices)
.Where(a => a.AppDataChoiceDl.Contains(groupName))
.Where(b => b.RequestApps.AppProvisioningCompleteTime != null)
.Where(c => c.RequestApps.AppTeamCompleteTime == null)
.Any(n => !n.RequestApps.AppStatus.Contains("Rejected"))).Select(reqInfo => new RequestInformation
{
ProvisioningCompleteTime = reqInfo.ProvisioningCompleteTime,
RequestMinistry = reqInfo.RequestMinistry,
UserFirstName = reqInfo.UserFirstName,
UserLastName = reqInfo.UserLastName,
SubmitterFirstName = reqInfo.SubmitterFirstName,
SubmitterLastName = reqInfo.SubmitterLastName,
RequestStatus = reqInfo.RequestStatus,
RequestApps = reqInfo.RequestApps
.Where(a => a.AppProvisioningCompleteTime != null)
.Where(b => b.AppTeamCompleteTime == null)
.Where(x => !x.AppStatus.Contains("Rejected"))
.Where(b => b.RequestAppDataChoices.Where(a => a.AppDataChoiceDl == groupName))
});
This throws an error not being able to convert IENUmerable to bool.. maybe I'm selecting my RequestAppDataChoices wrong?
This assumes you have a RequestInformationDto class that closely resembles your RequestInformation class:
var PullData = _context.RequestInformation.Include(x => x.RequestMinistry)
.Include(x => x.RequestApps)
.ThenInclude(x => x.RequestAppDataChoices)
.Where(x => x.RequestStatus != "Cancelled With Reason")
.Where(x => x.RequestApps.SelectMany(app => app.RequestAppDataChoices)
.Where(x => x.AppDataChoiceDl.Contains(groupName))
.Where(x => x.RequestApps.AppProvisioningCompleteTime != null)
.Where(x => x.RequestApps.AppTeamCompleteTime == null)
.Where(x => !x.RequestApps.AppStatus.Contains("Rejected")).Any())
.Select(reqInfo => new RequestInformationDto {
ProvisioningCompleteTime = reqInfo.ProvisioningCompleteTime,
RequestMinistry = reqInfo.RequestMinistry,
RequestApps = reqInfo.RequestApps
.Where(app => app.AppProvisioningCompleteTime != null)
.Where(app => app.AppTeamCompleteTime == null)
.Where(app => !app.AppStatus.Contains("Rejected")).Any())
.ToList()
UserFirstName = reqInfo.UserFirstName,
UserLastName = reqInfo.UserLastName,
SubmitterFirstName = reqInfo.SubmitterFirstName,
SubmitterLastName = reqInfo.SubmitterLastName,
RequestStatus = reqInfo.RequestStatus
});
I just noticed this part of your query, which should probably be reworked (or removed) as well:
.Where(x => x.RequestApps.SelectMany(app => app.RequestAppDataChoices)
.Where(x => x.AppDataChoiceDl.Contains(groupName))
.Where(x => x.RequestApps.AppProvisioningCompleteTime != null)
.Where(x => x.RequestApps.AppTeamCompleteTime == null)
.Where(x => !x.RequestApps.AppStatus.Contains("Rejected")).Any())
With Robert McKee's help, I was able to come up with this, that does work:
var PullData = _context.RequestInformation.Include(x => x.RequestMinistry)
.Include(x => x.RequestApps)
.ThenInclude(x => x.RequestAppDataChoices)
.Where(x => x.RequestStatus != "Cancelled With Reason")
.Where(x => x.RequestApps.SelectMany(app => app.RequestAppDataChoices)
.Where(a => a.AppDataChoiceDl.Contains(groupName))
.Where(b => b.RequestApps.AppProvisioningCompleteTime != null)
.Where(c => c.RequestApps.AppTeamCompleteTime == null)
.Any(n => !n.RequestApps.AppStatus.Contains("Rejected"))).Select(reqInfo => new RequestInformation
{
ProvisioningCompleteTime = reqInfo.ProvisioningCompleteTime,
RequestMinistry = reqInfo.RequestMinistry,
UserFirstName = reqInfo.UserFirstName,
UserLastName = reqInfo.UserLastName,
SubmitterFirstName = reqInfo.SubmitterFirstName,
SubmitterLastName = reqInfo.SubmitterLastName,
RequestStatus = reqInfo.RequestStatus,
RequestApps = reqInfo.RequestApps
.Where(a => a.AppProvisioningCompleteTime != null)
.Where(b => b.AppTeamCompleteTime == null)
.Where(x => !x.AppStatus.Contains("Rejected"))
.Where(b => b.RequestAppDataChoices.Any(a => a.AppDataChoiceDl == groupName)).ToList()
});

Linq to sql - nested select with groupby

I have the following SQL query:
SELECT * FROM [dbo].[Bil_Audit_BillingParameter] WHERE ([Status4Eyes]!='APPROVED' OR [Status4Eyes] IS NULL )AND
[LastComment] != '' AND
(Service='EUR' OR Service='S1') AND
[AudId] IN (SELECT MAX([AudId])
FROM [Bil_Audit_BillingParameter]
GROUP BY ID) UNION SELECT * FROM
[dbo].Bil_Audit_BillingParameter] WHERE ([Status4Eyes]!='APPROVED' OR [Status4Eyes] IS NULL) AND
[LastComment] != '' AND
(Service='EUR' OR Service='S1') AND
[AudId] IN (SELECT MIN([AudId])
FROM [Bil_Audit_BillingParameter]
GROUP BY ID)
How it is converting to linq? I tried the following , but ends up with error.
public IQueryable<ParameterUpdates> Get(ODataQueryOptions op)
{
var audIdMax = db.ParameterUpdates.GroupBy(x => x.ID).Select(v => v.Max(x => x.AudId));
var audIdMin = db.ParameterUpdates.GroupBy(x => x.ID).Select(a => a.Min(x => x.AudId));
var results1 = db.ParameterUpdates.Where(p => (!p.Status4Eyes.Contains("Approved") || string.IsNullOrEmpty(p.Status4Eyes)) &&
!p.LastComment.Contains("NULL") &&
(p.Service.Contains("EUR") || p.Service.Contains("S1")) &&
p.AudId.Equals(audIdMax));
var results2 = db.ParameterUpdates.Where(p => (!p.Status4Eyes.Contains("Approved") || string.IsNullOrEmpty(p.Status4Eyes)) &&
!p.LastComment.Contains("NULL") &&
(p.Service.Contains("EUR") || p.Service.Contains("S1")) &&
p.AudId.Equals(audIdMin));
var results = results1.Union(results2);
return results.AsQueryable();
}
Could anyone please help.
You can try this, first group by id create the filter output. Then inner join the filter with max or min audit id with the actual table and find the result.
var filter = ParameterUpdate.Where(p => (p.status == "Approved" || p.status == null)
&& p.lastComment != ""
&&(p.service=="EUR" || p.service=="S1")).GroupBy(p => p.id);
var result = (from p in ParameterUpdate
from f in filter
where p.auditId == f.Min(m => m.auditId) ||
p.auditId == f.Max(m => m.auditId)
select p);
public IQueryable<ParameterUpdates> Get()
{
var groupMax = db.ParameterUpdates
.GroupBy(u => u.ID)
.Select(grp => grp.Max(x => x.AudId));
var groupMin = db.ParameterUpdates
.GroupBy(u => u.ID)
.Select(grp => grp.Min(x => x.AudId));
var results = (db.ParameterUpdates.
Where(r => (r.Status4Eyes != "APPROVED" || r.Status4Eyes == null) &&
(r.LastComment != null) &&
(r.Service == "EUR" || r.Service == "S1") &&
(groupMax.Contains(r.AudId) || groupMin.Contains(r.AudId))
)).ToList();
return results.AsQueryable();

How to get conditional Include children entity and his related entity

The following code work for me:
var query0 = DB.Plan
.Include("UserCreate")
.Include("UserUpdate")
.Include("PlanTemplate")
.Select(p => new
{
plan = p,
planItems = p.PlanItems.Where(pi => pi.IsCommited == true && pi.IsLocked == false)
});
var query2 = query0.AsEnumerable().Where(m => m.planItems.Count() > 0).Select(m => m.plan);
But the planItems related to another entities that I wanted,the following code do not work for me:
var query0 = DB.WorkEffortPlan
.Include("UserCreate")
.Include("UserUpdate")
.Include("PlanTemplate")
.Select(p => new
{
plan=p,
planItems = DB.PlanItem
.Include("UserResponsiblePerson")
.Include("TemplateItem")
.Include("ItemState")
.Where(pi => pi.PlanID == p.PlanID && pi.IsCommited == true && pi.IsLocked == false)
});
var query2 = query0.AsEnumerable().Where(m => m.planItems.Count() > 0).Select(m => m.plan);
The vs compiler is run OK,but when exec this code,I get the NullReferenceException in query0.
Is there any linq solution to get filtering children entity and his related entity?

Resources