Using nested objects within query hits multiple indices in Nest ElasticSearch - nest

I have two types producttype and accounttype inside product and account indices, and I need to construct a search query to hit both of them.
Right now I have ended up with the following query:
var searchResponse = elasticClient.Search<object>(s => s
.Index(indices)
.Type(Types.Type(typeof(ProductType), typeof(accountType)))
.Query(q => q
q.Nested(n => n
.Path(Infer.Field<ProductType>(ff => ff.Keywords))
.Query(nq => nq
.Match(t => t
.Field(Infer.Field<ProductType>(ff => ff.Keywords.First().Keyword))
.Query(query)
)
||
nq.Term(Infer.Field<ProductType>(ff => ff.Keywords.First().Keyword.Suffix("keyword")), query)
)
)
&&
+q.Term("_type", "producttype")
||
q.MultiMatch(m => m
.Fields(f => f
.Field(Infer.Field<accountType>(ff => ff.AccountName, 1.5))
.Field(Infer.Field<accountType>(ff => ff.Description, 0.8))
)
.Operator(Operator.Or)
.Query(query)
) &&
+q.Term("_type", "accounttype")
)
);
When I run this query it doesn't work because of keywords nested object not found inside accounttype(but in my case I am filtering by _type so it should work).
So how can I filter by _index/_type when I have nested object inside one index?

Try by adding .IgnoreUnmapped(true) inside Nested object.
var searchResponse = elasticClient.Search<object>(s => s
.Index(indices)
.Type(Types.Type(typeof(ProductType), typeof(accountType)))
.Query(q => q
q.Nested(n => n
.IgnoreUnmapped(true)
.Path(Infer.Field<ProductType>(ff => ff.Keywords))
.Query(nq => nq
.Match(t => t
.Field(Infer.Field<ProductType>(ff => ff.Keywords.First().Keyword))
.Query(query)
)
||
nq.Term(Infer.Field<ProductType>(ff => ff.Keywords.First().Keyword.Suffix("keyword")), query)
)
)
&&
+q.Term("_type", "producttype")
||
q.MultiMatch(m => m
.Fields(f => f
.Field(Infer.Field<accountType>(ff => ff.AccountName, 1.5))
.Field(Infer.Field<accountType>(ff => ff.Description, 0.8))
)
.Operator(Operator.Or)
.Query(query)
) &&
+q.Term("_type", "accounttype")
)
);

Related

how to write a linq with multiple join

as am a beginner,i want to get the following set of query as linq with a detailed explanation
//my sql
select COL.title as organizationtitle,CL.[title] as
cousestitle,sum(FD.feathers) as totalfeathers,sum(FD.amount) as
totalamount
from [dbo].[FeathersDonated] FD
join [dbo].[Couses] C on FD.corpid=3 and FD.[cousesid]=C.id
join [dbo].[Couses_lang] CL on FD.[cousesid]=CL.cousesid and
CL.language='en-US'
JOIN [dbo].[Organization_lang] COL on COL.orgid=2 and COL.language='en
US'
group by FD.cousesid,CL.[title],CL.[description],COL.title
i have tried the following set of code. please do help
var featherDonated = _GoUoW.FeathersDonated.FindBy(x => x.corpid ==
param.corpid)
.GroupBy(x => x.cousesid).Select(x => new { cousesid = x.Key, amount =
x.Select(a => a.amount).DefaultIfEmpty(0).Sum(), feathers = x.Select(a =>
a.feathers).DefaultIfEmpty(0).Sum() })
.Join(_GoUoW.Couses.GetAll(), feather => feather.cousesid, couse =>
couse.id, (feather, couse) => new { feather, couse })
.Join(_GoUoW.Organization_lang.FindBy(orglang => orglang.language == "en-
US"), couses => couses.couse.orgid, orgid => (param.organizationid > 0 ?
param.organizationid : orgid.orgid), (couses, orgid) => new { couses,
orgid
})
.Join(_GoUoW.Couses_lang.FindBy(couselang => couselang.language == "en-
US"),
organization => organization.orgid.orgid, couselang => couselang.cousesid,
(organization, couselang) => new { organization, couselang })
.Select(x => new
{
x.organization.couses.feather.amount,
x.organization.couses.feather.feathers,
x.couselang.title
//x.organization.orgid.title,
}).ToList();

NHibernate projection: How to create AliasToBean projection?

I am trying to convert this inefficient query into one that projects into a dto.
Original query looks like this:
var flatFeePolicies = _session.QueryOver<FlatChargeAccessFee>(() => flatChargeAccessFeeAlias)
.JoinAlias(x => x.AgreementAccessFee, () => agreementAccessFeeAlias)
.JoinQueryOver(x => x.ClientPolicy, () => clientPolicyAlias)
.Where(y => agreementAccessFeeAlias.Agreement.Id == request.AgreementId)
.List()
.Select(x => new FlatChargeAccessFeeInfo()
{
FlatChargeAccessFeeId = x.Id,
ClientName = x.ClientPolicy.Bid.Client.Name,
PolicyNumber = x.ClientPolicy.PolicyNumber,
ClientPolicyId = x.ClientPolicy.Id,
AgreementAccessFeeId = x.AgreementAccessFee.Id,
ShouldCheckBeGenerated = x.ShouldCheckBeGenerated,
MonthlyFee = x.MontlyFeeAmount.Amount.ToString(),
PolicyYear = x.ClientPolicy.PolicyNumber.Year
})
.ToList();
I tried it like this:
var flatFeePolicies = _session.QueryOver<FlatChargeAccessFee>(() => flatChargeAccessFeeAlias)
.JoinAlias(x => x.AgreementAccessFee, () => agreementAccessFeeAlias)
.JoinQueryOver(x => x.ClientPolicy, () => clientPolicyAlias)
.Where(y => agreementAccessFeeAlias.Agreement.Id == request.AgreementId)
.SelectList(list => list
.Select(x => x.Id).WithAlias(() => feeInfo.FlatChargeAccessFeeId)
.Select(x => x.ClientPolicy.Bid.Client.Name).WithAlias(() => feeInfo.ClientName)
.Select(x => x.ClientPolicy.PolicyNumber).WithAlias(() => feeInfo.PolicyNumber)
.Select(x => x.ClientPolicy.Id).WithAlias(() => feeInfo.ClientPolicyId)
.Select(x => x.AgreementAccessFee.Id).WithAlias(() => feeInfo.AgreementAccessFeeId)
.Select(x => x.ShouldCheckBeGenerated).WithAlias(() => feeInfo.ShouldCheckBeGenerated)
.Select(x => x.MontlyFeeAmount.Amount.ToString()).WithAlias(() => feeInfo.MonthlyFee)
.Select(x => x.ClientPolicy.PolicyNumber.Year).WithAlias(() => feeInfo.PolicyYear)
)
.TransformUsing(Transformers.AliasToBean<FlatChargeAccessFeeInfo>())
.List<FlatChargeAccessFeeInfo>();
and I am getting an error that variable "x" has been referenced in scope but was not defined. What is the proper syntax to convert this?
After help from Andrew, here is the correct version that works
ClientPolicy clientPolicyAlias = null;
Client clientAlias = null;
Bid bidAlias = null;
AgreementAccessFee agreementAccessFeeAlias = null;
FlatChargeAccessFee flatChargeAccessFeeAlias = null;
FlatChargeAccessFeeInfo feeInfo = null;
var flatFeePolicies = _session.QueryOver<FlatChargeAccessFee>(() => flatChargeAccessFeeAlias)
.JoinAlias(a => a.AgreementAccessFee, () => agreementAccessFeeAlias)
.JoinQueryOver(b => b.ClientPolicy, () => clientPolicyAlias)
.JoinAlias(b=>b.Bid,()=>bidAlias)
.JoinAlias(b=>b.Client, ()=>clientAlias)
.Where(c => agreementAccessFeeAlias.Agreement.Id == request.AgreementId)
.SelectList(list => list
.Select(d => d.Id).WithAlias(() => feeInfo.FlatChargeAccessFeeId)
.Select(e => clientAlias.Name).WithAlias(() => feeInfo.ClientName)
.Select(e => clientAlias.Number).WithAlias(() => feeInfo.ClientNumber)
.Select(f => bidAlias.OptionNumber).WithAlias(() => feeInfo.BidOptionNumber)
.Select(f => bidAlias.Year).WithAlias(()=>feeInfo.PolicyYear)
.Select(g => clientPolicyAlias.Id).WithAlias(() => feeInfo.ClientPolicyId)
.Select(h => agreementAccessFeeAlias.Id).WithAlias(() => feeInfo.AgreementAccessFeeId)
.Select(j => j.ShouldCheckBeGenerated).WithAlias(() => feeInfo.ShouldCheckBeGenerated)
.Select(k => k.MontlyFeeAmount.Amount).WithAlias(()=>feeInfo.MonthlyFee)
)
.TransformUsing(Transformers.AliasToBean<FlatChargeAccessFeeInfo>())
.List<FlatChargeAccessFeeInfo>();
You're close, a few things though:
This select:
.Select(x => x.MontlyFeeAmount.Amount.ToString()).WithAlias(() => feeInfo.MonthlyFee)
will not work. QueryOver attempts to turn your code directly into SQL. If the property does not exist as a column in the database, the query won't work properly (unless you're using a mapped custom type, QueryOver can handle those)
Nested property access won't work either:
.Select(x => x.ClientPolicy.Bid.Client.Name).WithAlias(() => feeInfo.ClientName)
for a similar reason listed above. QueryOver will attempt to turn your property access directly into SQL. You'll need to explicitly join from ClientPolicy to Bid to Client.
In general, remember that you're writing code that's going to be turned into SQL. In fact, I normally write the SQL I want to generate first and then write the QueryOver that corresponds to that. Hope that helps!

fluent hibernate Transformers.AliasToBean is not working as expected

I have three tables. One is the master table: TableA. One table is referenced by TableA called ReferencedTable and lastly a lookup table referenced by ReferencedTable.
I have this query that returns the ten most recent objects as:
TableADTO TableAlias = null;
LookupTableDTO LookupTableAlias = null;
ReferencedDTO ReferencedAlias = null;
dtos = session.QueryOver(() => TableAlias)
.JoinAlias(() => TableAlias.Object, () =>ReferencedAlias)
.JoinAlias(() => ReferencedAlias.ObjectType, () => LookupTableAlias)
.Where(() => ReferencedAlias.PersonId == user.Id &&
(LookupTableAlias.Id != INVOICE_ID ||
LookupTableAlias.Id != FINANCIAL_ID) &&
TableAlias.Status == NEW_STATUS_FLAG &&
ReferencedAlias.ReceivedDate < DateTime.Now)
.Take(10)
.List()
.Select(dto=>
new AbreviatedDTO
{
Id = dto.Referenced.Id,
Field1 = dto.Field1,
Priority = dto.Referenced.Priority,
ReceivedDate = dto.Referenced.ReceivedDate,
Field1 = dto.Referenced.Field1,
Type = dto.Referenced.Lookup.TypeCode,
Status = dto.Status
}).ToList();
This works as expected. However, I thought the the transformation below would work too. It does bring 10 objects but the objects have all default values and are not populated (e.g. AbreviatedDTO.ReceivedDate = DateTime.Minimum). Am I doing something wrong with the QueryOver?
Any help would be appreciated.
Bill N
TableDTO TableAlias = null;
LookupTableDTO LookupTableAlias = null;
ReferencedDTO ReferencedAlias = null;
dtos = session.QueryOver(() => TableAlias)
.JoinAlias(() => TableAlias.Object, () =>ReferencedAlias)
.JoinAlias(() => ReferencedAlias.ObjectType, () => LookupTableAlias)
.Where(() => ReferencedAlias.PersonId == user.Id &&
(LookupTableAlias.Id != INVOICE_ID ||
LookupTableAlias.Id != FINANCIAL_ID) &&
TableAlias.Status == NEW_STATUS_FLAG &&
ReferencedAlias.ReceivedDate < DateTime.Now)
.SelectList(list => list
.Select(x => TableAlias.Field1)
.Select(x => ReferencedAlias.Id)
.Select(x => ReferencedAlias.Field1)
.Select(x => ReferencedAlias.ReceivedDate)
.Select(x => ReferencedAlias.Priority)
.Select(x => LookupTableAlias.TypeCode))
.TransformUsing(Transformers.AliasToBean<AbreviatedDTO>())
.Take(10)
.List<AbreviatedDTO>()
you'll need to define an alias for each selected field same as the propertyname in the resulting dto
AbreviatedDTO alias = null;
// in query
.SelectList(list => list
.Select(() => TableAlias.Field1).WithAlias(() => alias.Field1)

Nhibernate QueryOver: Count in where clause

Any tips on how to convert the following to QueryOver:
var widget = session.Query<Widget>()
.Fetch(x => x.NotificationJobs)
.Where(x =>
x.Status == Status.Active &&
!x.NotificationJobs.Any())
.OrderByDescending(x => x.DateCreated)
.Take(1)
.SingleOrDefault();
Want to get a widget that has no notification jobs.
var widgetWithNoNotificationJob = session.QueryOver<Widget>()
.Where( x => x.Status == Status.Active )
.OrderBy( x => x.DateCreated ).Desc
.Left.JoinQueryOver<NotificationJob>( x => x.NotificationJobs )
.Where( x => x.NotificationJobId == null )
.Take( 1 )
.SingleOrDefault();
This will produce SQL with a LEFT OUTER JOIN on the NotificationJob table and a WHERE clause with NotificationJob.NotificationJobId IS NULL.
Hopefully this will point you in the right direction.

I can't avois this select N+1

I have this mapping ( it comes from adventureworks since I used it in a demo app for an automatic paging collection )
ModelMapper mapper = new ModelMapper(new SimpleModelInspector());
mapper.Class<Contact>(
k => {
k.Id(i => i.ContactID, m => m.Generator(Generators.Native));
k.Schema("Person");
}
);
mapper.Class<Employee>(
k =>
{
k.Id(i => i.EmployeeID, m => m.Generator(Generators.Native));
k.Schema("HumanResources");
k.ManyToOne(c => c.Contact, m => m.Column("ContactID"));
}
);
mapper.Class<SalesOrderHeader>(
k =>
{
k.Id(i => i.SalesOrderID,m=>m.Generator(Generators.Native));
k.Schema("Sales");
k.ManyToOne(c => c.SalesPerson, m => m.Column("SalesPersonID"));
k.ManyToOne(c => c.Contact, m => m.Column("ContactID"));
}
);
var map = mapper.CompileMappingForAllExplicitlyAddedEntities();
cfg.AddDeserializedMapping(map,string.Empty);
and the following ( limited ) query:
var list = NHHelper.Instance.CurrentSession.Query<SalesOrderHeader>()
.Fetch(k => k.Contact)
.Fetch(k => k.SalesPerson)
.Skip(first)
.Take(count)
.ToList();
I can't remove the select N+1 caused by employee-contact, how can I do ?
Consider mapping too can be changed !
EDIT: I add the working solution by #cremor
var list = NHHelper.Instance.CurrentSession.Query<SalesOrderHeader>()
.Fetch(k => k.Contact)
.Fetch(k => k.SalesPerson).ThenFetch(k=>k.Contact)
.Skip(first)
.Take(count)
.ToList();
this will avoid the problem.
Adding .ThenFetch(c => c.Contact) after .Fetch(k => k.SalesPerson) should also fetch the Contact of the Employee.