Query returning same customer - c#

I have two records for the same customer but with different customerLastUpdated dates, there is a way to return only the most recent one?
var response = await this.client.SearchAsync<ElasticCustomer>(searchDescriptor => searchDescriptor
.AllTypes()
.Query(q => q.Bool(b => b
.Should(
sh => sh.Match(m => m.Field(f => f.CustomerName).Query(query)),
sh => sh.Wildcard(w => w.Field(f => f.MobileNumber.Suffix("keyword")).Value($"*{query}*")))));

Related

How to iterate fields as per coming input fields in NEST queries?

I written my NEST query like below
var searchResponse = await _elasticClient.SearchAsync<T>(s => s
.Index(indexName)
.Query(q => q
.Bool(b => b
.Should(
sh => sh.Prefix(pr => pr.Field(fieldNames[0]).Value(fieldValues[0])),
sh => sh.Prefix(pr => pr.Field(fieldNames[1]).Value(fieldValues[1]))
)
))
.Aggregations(ag=>ag.Cardinality(sumName,ca=>ca.Field(cardinalField)))
.Collapse(co=>co.Field(cardinalField))
).ConfigureAwait(false);
return searchResponse.Count;
}
I need to iterate below code
sh => sh.Prefix(pr => pr.Field(fieldNames[0]).Value(fieldValues[0])),
sh => sh.Prefix(pr => pr.Field(fieldNames[1]).Value(fieldValues[1]))
as per input array
I tried like below
private static QueryContainer MatchAny<T>(QueryContainerDescriptor<T> descriptor, Field[] fields, string value) where T : class
{
QueryContainer q = new QueryContainer();
for (int i=0;i<=fields.Length-1;i++)
{
q |= descriptor.Match(t => t.Field(fields[i]).Query(value));
}
return q;
}
var searchResponse = await _elasticClient.SearchAsync<T>(s => s
.Index(indexName)
.Query(q => q
.Bool(b => b
.Should(sh=> MatchAny(sh, fieldNames, fieldValue)
)
))
).ConfigureAwait(false);
but getting compile error :
cannot convert from 'string[]' to 'Nest.Field[]'
so how to iterate fields as per coming no of inputs in NEST queries ?

C# NEST nested filter to get values within the dateRange or NULL

I am developing something to show a pie chart of the users' age with slicing them as
0-17
18-34
35-44
44-54
55+
Not Available
here i am getting the ages based on the date range;
var aggaResonse = client.Search<JSModel>(a => a
.Size(0)
.Query(q => q.Bool(b => b.Must(m => m
.DateRange(date => date
.Field(p => p.CreatedDate)
.GreaterThanOrEquals(start)
.LessThanOrEquals(end)),
m =>
m.Term(t => t.Field(f => f.StepType.Suffix("keyword")).Value("User"))
)
))
.Aggregations(c => c.DateRange(nameof(AgeModel), x => x
.Field(f => f.BirthDate)
.Ranges(r => r.From(DateMath.Now.Subtract("17y")).To(DateMath.Now).Key(nameof(result.Years_0_17)),
r => r.From(DateMath.Now.Subtract("34y")).To(DateMath.Now.Subtract("18y")).Key(nameof(result.Years_18_34)),
r => r.From(DateMath.Now.Subtract("44y")).To(DateMath.Now.Subtract("35y")).Key(nameof(result.Years_35_44)),
r => r.From(DateMath.Now.Subtract("54y")).To(DateMath.Now.Subtract("45y")).Key(nameof(result.Years_45_54)),
r => r.From(DateMath.Now.Subtract("120y")).To(DateMath.Now.Subtract("55y")).Key(nameof(result.Years_55_Plus))
)
)
));
if (!aggaResonse.IsValid)
return result;
result.Years_0_17 = aggaResonse.Aggregations.Range(nameof(AgeModel)).Buckets.Single(c => c.Key == nameof(result.Years_0_17)).DocCount;
result.Years_18_34 = aggaResonse.Aggregations.Range(nameof(AgeModel)).Buckets.Single(c => c.Key == nameof(result.Years_18_34)).DocCount;
result.Years_35_44 = aggaResonse.Aggregations.Range(nameof(AgeModel)).Buckets.Single(c => c.Key == nameof(result.Years_35_44)).DocCount;
result.Years_45_54 = aggaResonse.Aggregations.Range(nameof(AgeModel)).Buckets.Single(c => c.Key == nameof(result.Years_45_54)).DocCount;
result.Years_55_Plus = aggaResonse.Aggregations.Range(nameof(AgeModel)).Buckets.Single(c => c.Key == nameof(result.Years_55_Plus)).DocCount;
return result;
what i need is to have a "Not Available" slice for users who has NULL as birthdate with mapping it as;
result.Not_Available = ....;
Any suggestions with following best practices for nested NEST aggs ?
I was thinking to run another search which i guess it's not the best practice.
After digging documentations too much, here is the solution i wrote;
I added a "Missing" attribute to the current aggregation;
&& c.Missing("DOBMissing", x => x.Field(f => f.BirthDate))
So it became like;
.Aggregations(c => c.DateRange(nameof(AgeModel), x => x
.Field(f => f.BirthDate)
.Ranges(r => r.From(DateMath.Now.Subtract("17y")).To(DateMath.Now).Key(nameof(result.Years_0_17)),
r => r.From(DateMath.Now.Subtract("34y")).To(DateMath.Now.Subtract("18y")).Key(nameof(result.Years_18_34)),
r => r.From(DateMath.Now.Subtract("44y")).To(DateMath.Now.Subtract("35y")).Key(nameof(result.Years_35_44)),
r => r.From(DateMath.Now.Subtract("54y")).To(DateMath.Now.Subtract("45y")).Key(nameof(result.Years_45_54)),
r => r.From(DateMath.Now.Subtract("120y")).To(DateMath.Now.Subtract("55y")).Key(nameof(result.Years_55_Plus))
)
) &&
c.Missing("DOBMissing", x => x.Field(f => f.BirthDate))
)
And i'd accessed the "missing" part of aggregation as following;
result.Not_Available = aggaResponse.Aggregations.Missing("DOBMissing").DocCount;

EFCore Query and selection

Hey I am trying to query and find a object that looks something like this:
I have already result
I have id that is quiz id.
So i have both Ids.
var singlequiz = await _context.Quizzes
.Include(q => q.Questions)
.ThenInclude(question => question.Options)
.Include(qz => qz.Results)
.Where(b => b.Id == id)
.Select(c => c.Results.Select(z => z.Id == result.Id))
.FirstOrDefaultAsync();
What I am trying to do here is : find an object with id X, then that object with id X has a list of results, I want to get the list, BUT with only the one element that has id of result.Id.
What am i doing wrong?
EDIT:
Used this ATM
var singlequiz = await _context.Quizzes
.Include(x => x.Questions)
.ThenInclude(x => x.Options)
.Include(x => x.Results)
.FirstOrDefaultAsync(x => x.Id == id);
var singleQuizElement = singlequiz.Results.Where(x => x.Id == result.Id).ToList();
singlequiz.Results = singleQuizElement;
Try this :
var singlequiz = await _context.Quizzes
.Include(x => x.Questions)
.ThenInclude(x => x.Options)
.Include(x => x.Results)
.FirstOrDefaultAsync(x=> x.Id == id && x.Results.Any(y => y.Id == result.Id));

Linq query fine tuning

Query logic is Grouping the items by Id and Ordering it by Id. Then inside grouped items Ordering by Item1 then by Item2.
Linq query below,
var group1Items = MyList.GroupBy(g => g.Id)
.Where(w => w.Any(a => a.Code = 1)
.Select(s => new
{ key = s.Key,
items = s.OrderBy(o => o.Item1)
.ThenBy(t => t.Item2)
}
)
.OrderBy(o => o.Id)
.SelectMany(sm => sm.Items).ToList();
var group2Items = MyList.GroupBy(g => g.Id)
.Where(w => w.Any(a => a.Code = 2)
.Select(s => new
{ key = s.Key,
items = s.OrderBy(o => o.Item1)
.ThenBy(t => t.Item2)
}
)
.OrderBy(o => o.Id)
.SelectMany(sm => sm.Items).ToList();
MyList.Clear();
MyList.InsertRange(Mylist.Count, group1Items);
MyList.InsertRange(Mylist.Count, group2Items);
In the above two queries, only difference is Where condition. Is it possible to rewrite into single query?
Single query:
var groupItems = MyList.GroupBy(g => g.Id)
.Where(w => w.Any(a => a.Code == 1 || a.Code == 2)
.Select(s => new
{ key = s.Key,
items = s.OrderBy(o => o.Item1)
.ThenBy(t => t.Item2)
}
)
.OrderBy(o => o.Id)
.SelectMany(sm => sm.Items).ToList();
If Code 1 must come before Code 2:
var groupItems = MyList.GroupBy(g => g.Id)
.Where(w => w.Any(a => a.Code == 1)
.Select(s => new
{ key = s.Key,
items = s.OrderBy(o => o.Item1)
.ThenBy(t => t.Item2)
}
)
.OrderBy(o => o.Id)
.SelectMany(sm => sm.Items)
.Union(MyList.GroupBy(g => g.Id)
.Where(w => w.Any(a => a.Code == 2)
.Select(s => new
{ key = s.Key,
items = s.OrderBy(o => o.Item1)
.ThenBy(t => t.Item2)
}
)
.OrderBy(o => o.Id)
.SelectMany(sm => sm.Items)).ToList();
If you only want to avoid code duplication it may be easiest to capture a variable holding the code by which to filter.
int code = 0; // initialize with any value
var groupItems = MyList.GroupBy(g => g.Id)
.Where(w => w.Any(a => a.Code == code)
.Select(s => new
{
key = s.Key,
items = s.OrderBy(o => o.Item1)
.ThenBy(t => t.Item2)
})
.OrderBy(o => o.Id)
.SelectMany(sm => sm.Items); // No ToList() here!
MyList.Clear();
code = 1;
MyList.InsertRange(Mylist.Count, groupItems.ToList());
code = 2;
MyList.InsertRange(Mylist.Count, groupItems.ToList());
Removed where clause in the LINQ expression and implemented at InsertRange() method. This avoids redundant queries
var groupItems = MyList
.GroupBy(g => g.Id)
.Select(s => new
{ key = s.Key,
items = s.OrderBy(o => o.Item1)
.ThenBy(t => t.Item2)
}
)
.OrderBy(o => o.Id)
.SelectMany(sm => sm.Items).ToList();
MyList.Clear();
MyList.InsertRange(Mylist.Count, groupItems.Where(w => w.Code == 1));
MyList.InsertRange(Mylist.Count, groupItems.Where(w => w.Code == 2));

Handle null values in queryover projections

I have a counterpart, which has an address, which MIGHT have a country assigned.
How do I handle this:
InvoiceAddress invoiceAddres = null;
Country InvoiceAddressCountry = null;
Counterpart counterpart = null;
CounterpartTabDTO result = null;
// projections for DTO-mapping
var projections = new[]
{
Projections.Property(() => counterpart.CounterpartId).WithAlias(() => result.InternalID),
Projections.Property(() => counterpart.GlobalCounterpartId).WithAlias(() => result.BasicInfo_GlobalCounterpartyID),
Projections.Property(() => counterpart.Name).WithAlias(() => result.BasicInfo_Name),
Projections.Property(() => counterpart.ShortName).WithAlias(() => result.BasicInfo_ShortName),
Projections.Property(() => counterpart.PhoneNumber).WithAlias(() => result.BasicInfo_Telephone),
Projections.Property(() => counterpart.Webpage).WithAlias(() => result.BasicInfo_WWW),
Projections.Property(() => counterpart.Language).WithAlias(() => result.BasicInfo_Language),
Projections.Property(() => counterpart.VAT).WithAlias(() => result.BasicInfo_VAT),
Projections.Property(() => counterpart.CompanyRegistrationNumber).WithAlias(() => result.BasicInfo_CompanyRegistationno),
Projections.Property(() => invoiceAddres.Name).WithAlias(() => result.BasicInfo_InvoiceAddressContactPerson),
Projections.Property(() => invoiceAddres.Street).WithAlias(() => result.BasicInfo_InvoiceAddressAddress),
Projections.Property(() => invoiceAddres.PostalCode).WithAlias(() => result.BasicInfo_InvoiceAddressPostalCode),
Projections.Property(() => invoiceAddres.City).WithAlias(() => result.BasicInfo_InvoiceAddressCity),
Projections.Property(() => invoiceAddres.Area).WithAlias(() => result.BasicInfo_InvoiceAddressArea),
Projections.Property(() => InvoiceAddressCountry.PrintableName).WithAlias(() => result.BasicInfo_InvoiceAddressCountry),
Projections.Property(() => invoiceAddres.Department).WithAlias(() => result.BasicInfo_InvoiceAddressDepartment),
Projections.Property(() => invoiceAddres.Fax).WithAlias(() => result.BasicInfo_InvoiceAddressFax),
Projections.Property(() => invoiceAddres.MainEmail).WithAlias(() => result.BasicInfo_InvoiceAddressEmail),
};
var query = Session.QueryOver(() => counterpart)
.JoinQueryOver<InvoiceAddress>(x => x.InvoiceAddresses, () => invoiceAddres)
.Where(x => x.IsDefault)
.JoinQueryOver<Country>(() => invoiceAddres.Country, () => InvoiceAddressCountry)
.Select(projections);
The issue is InvoiceAddressCountry, which might be null. If that happens, I'd like the result.BasicInfo_InvoiceAddressCountry property stays null.
To clarify, the above code does not work. It can't handle the null.
From your words I can suppose that you'll need to use left join:
.Left.JoinQueryOver(() => invoiceAddres.Country, () => InvoiceAddressCountry)

Categories

Resources