Exclude nulls in Nest Api query - c#

I have added the following snippet in a nest query which returns a ISearchResponse<T>
.Query(query => query.Match(m =>
m.Field(f =>
f => !string.IsNullOrEmpty(f.Purchase.NationalCode.Trim()))
)))
But it makes no difference to the amount of records returned (and I know there are nulls in there)
Should I do be building my query some other way?
Edited to add:
I've tried the following based on this answer here but no luck either
.Query(query => query.Bool(b=>
b.Must(m=> m.Exists(
f=>f.Field("nationalCode")))))
.Query(query => query.Bool(b=>
b.MustNot(m=> m.Term(
"nationalCode", ""))))

Try the following
.Query(query => query
.Bool(b => b
.Must(m => m
.Exists(f => f.Field("nationalCode"))
)
.MustNot(m => m
.Term("nationalCode", "")
)
)
)
Both the .Must and .MustNot need to be called on the same bool query descriptor

Related

Elasticsearch / Nest search using MultiMatch with default boosting for all other fields

I'm trying to build a query that basically searches over all full text fields, boosting a few, but leaving all others at the default boost of 1.
When I don't include any fields, everything has a boost of 1 (we're on version 6.4.2 which supports default when no fields are specified):
var results = await _ElasticClient.SearchAsync<dynamic>(s => s
.Query(q => q
.MultiMatch(m => m
.Query(request.Query)
)
)
);
However, as soon as I try to boost a single field, it removes the defaults on all the other fields, only searching on the explicit field:
var results = await _ElasticClient.SearchAsync<dynamic>(s => s
.Query(q => q
.MultiMatch(m => m
.Fields(f => f.Field("firstName^20"))
.Query(request.Query)
)
)
);
I tried adding a wildcard, but this still just matches on firstName (then again, the wildcard on its own doesn't match anything, so assuming I have the syntax wrong on that):
var results = await _ElasticClient.SearchAsync<dynamic>(s => s
.Query(q => q
.MultiMatch(m => m
.Fields(f => f.Field("*.*^1"))
.Fields(f => f.Field("firstName^20"))
.Query(request.Query)
)
)
);
I also tried Booling them together, but this also just matches on firstName:
var results = await _ElasticClient.SearchAsync<dynamic>(s => s
.Query(q => q
.Bool(b => b
.Should(m => m
.MultiMatch(mm => mm
.Query(request.Query)
)
)
.Should(m => m
.MultiMatch(mm => mm
.Fields(f => f.Field("firstName^20"))
.Query(request.Query)
)
)
)
)
);
I'm starting to think this isn't possible. For context, the reason I'm trying to do this is to be able to add other full text fields to the index without having to include every field in our queries, but still be able to boost certain fields.
Figured out my problem. I was chaining multiple .Fields() (plural) together, where I should only have a single .Fields() (plural) and then chain multiple .Field() (singular) together:
var results = await _ElasticClient.SearchAsync<dynamic>(s => s
.Query(q => q
.MultiMatch(m => m
.Fields(f => f
.Field("firstName^20")
.Field("*.*^1")
)
.Query(request.Query)
)
)
);

C# Nest Elastic Search Wildcard Query - No Results Returned

I'm trying to set up a query in C# using a wildcard. I can get the correct data returned using MultiMatch but have not had success with wildcard. Here is what I have so far:
public async Task<IEnumerable<SearchResultModel>> Search(string query)
var queryResults = await elasticApp.SearchAsync<dynamic>(s => s
.From(0)
.Take(10)
.Index(activeIndices)
.Type(dataTypes)
.Query(q => q
.Bool(b => b
.Should(m => m
.Wildcard(w => w
.Field("name")
.Value(w + "*")
)
)
)
)
So as for the function parameter query when using MultiMatch, you would do .Query(query) at the end, but when I try to put that in using Wildcard I get syntax errors. And according to the NEST ES docs it seems that you do not use .Query at the end.
Currently an empty array is returned.
Any insight on this would be appreciated as I am new to using Nest and C#.
I was able to resolve my issue by doing the following:
.Query(q => q
.Bool(b => b
.Should(m => m
.Wildcard(c => c
.Field("name").Value(query.ToLower() + "*")
)
)
)
)
query is passed in as a function argument and I want the asterisk to take everything after query.

Elastic Nest Adding Meta to Aggregations

I am successfully creating Aggregations with my Elastic NEST query but I would like to pass some additional information in I have seen that I can use Meta for this, but I cannot find any documentation for doing it in NEST.
HERE is my nest Aggregations code
.Aggregations(aa => aa.Terms("groups", sp => sp.Field(p => p.ProductSpecification.Suffix("name"))
.Aggregations(aaa => aaa
.Terms("attribute", tt => tt.Field(ff => ff.ProductSpecification.Suffix("value"))))
Basically id like to be add say SpecificationId to the meta any hints?
You can add meta per aggregation, and it'll be returned on the aggregation response
var response = client.Search<User>(s => s
.Size(0)
.Query(q => +q
.Term(m => m
.Field(f => f.Badges.First().Name)
.Value("c#")
)
)
.Aggregations(a => a
.SignificantTerms("badges", st => st
.Field(f => f.Badges.First().Name)
.Meta(m => m
.Add("meta_1", "value_1")
.Add("meta_2", 2)
)
)
)
);

How to factorize a Linq request with multiple includes?

I want to simplify a linq Query that contains multiple includes.
My model is simple: a site is linked to one contract, that is linked to one client. On that client I need to get with a single request the telephones, mails and honorifics (appelRef).
I want a single request because behind the request is translated by entity framework into a SQL Server request.
Here is the linq request:
var search =
from IMT.Site s in imtContext.IMTObjects.OfType<IMT.Site>()
.Include(
s => s.LienContratSiteRef
.Select(l => l.Contrat)
.Select(c => c.LienContratClientRef
.Select(l => l.Client)
.Select(cl => cl.Telephones ) ) )
.Include(s => s.LienContratSiteRef
.Select(l => l.Contrat)
.Select(c => c.LienContratClientRef
.Select(l => l.Client)
.Select(cl => cl.Mails ) ) )
.Include(s => s.LienContratSiteRef
.Select(l => l.Contrat)
.Select(c => c.LienContratClientRef
.Select(l => l.Client)
.Select(cl => cl.AppelRef ) ) )
where s.Reference.ToString() == siteId
select s;
Yor can notice the block
.Include(
s => s.LienContratSiteRef
.Select(l => l.Contrat)
.Select(c => c.LienContratClientRef
.Select(l => l.Client)
..is repeated three time. Is ther a way to factorize that code block ?
Update: there are intermedray objects LienContratSiteRef and LienContratClientRef and relationships are 0 - *, so that LienContratSiteRef.Contrat and LienContratClientRef.Client are collections.
I also tried:
.Include(
s => s.LienContratSiteRef
.Select(l => l.Contrat)
.Select(c => c.LienContratClientRef
.Select(l => l.Client)
.Select(cl => new { Tels = cl.Telephones, Mail = cl.Mails, Appel = cl.AppelRef} ) ) )
but It results with a runtime error:
The Include path expression must refer to a navigation property
defined on the type.
The s => ... inside the include could be refactored into a delegate, then just .Include that delegate multiple times.
It looks like the signature would be Func<Site, IEnumerable<Client>>?
E.g.
static IEnumerable<Client> Foo(Site site) => site.LienContratSiteRef
.Select(l => l.Contrat)
.Select(c => c.LienContratClientRef
.Select(l => l.Client)
String-based Chaining
The Include() method supports a dot-delimited string parameter which can be used to pull an complete graph of objects down as opposed to making multiple chained select calls:
.Include("LienContratSiteRif.Contrat.LienContratClientRef.Client")
From there, if you wanted to include multiple additional properties, I believe that you could have another include for those sub properties:
.Include("LienContratSiteRif.Contrat.LienContratClientRef.Client, Client.Telephones, ...")
Lambda-based Chaining
You should be able to accomplish something similar by chaining your lambda-based includes into a single Include() call as well using:
.Include(c => LienContratSiteRif.Contrat.LienContratClientRef.Client)
It looks like you're trying to make an entity framework projection!
A project allows you to select only the properties that you want to return. (just like a SQL Select)
To use a projection, your code should roughly look like this:
var search = imtContext.IMTObjects.OfType<IMT.Site>()
.Where(s => s.Reference.ToString() == siteId)
.Select(s => new {
Telephones = s.LienContratSiteRef.Contrat.Select(c => c.LienContratClientRef.Client.Select(cli => cli.Telephones),
Mails = s.LienContratSiteRef.Contrat.Select(c => c.LienContratClientRef.Client.Select(cli => cli.Mails),
AppelRef = s.LienContratSiteRef.Contrat.Select(c => c.LienContratClientRef.Client.Select(cli => cli.AppelRef)
}).ToList();
If Telephones, Mails, AppelRefare also collections, then you can do aggregate the collections together like this in memory after the query has been run:
var telephones = search.SelectMany(x => x.Telephones).ToList();
var mails = search.SelectMany(x => x.Mails).ToList();
var appelRefs = search.SelectMany(x => x.AppelRef).ToList();

NHibernate: Could not resolve property error

I am trying to do a query like:
var a = session.QueryOver<Site>()
.SelectList(
x => x.Select(p => p.SiteName)
.Select(p => p.SiteId).Select(p => p.RegionLocation.City))
.List<object[]>();
but I get the error
could not resolve property: RegionLocation.City of: Entities.Site
The property exists and I can retrieve it using LINQ but QueryOver does not work. What am I doing wrong ?
As far as i remember, with QueryOver, you have to join all entities in the association in order to be able to access it's properties.
This means you ought to do something like:
(notice the .JoinQueryOver)
var a = session.QueryOver<Site>()
.JoinQueryOver(s => s.RegionLocation)
.SelectList(
x => x.Select(p => p.SiteName)
.Select(p => p.SiteId)
.Select(p => p.RegionLocation.City))
.List<object[]>();
Or maybe this will work:
RegionLocation regionLocationAlias = null;
var a = session.QueryOver<Site>()
.JoinAlias(s => s.RegionLocation, () => regionLocationAlias)
.SelectList(
x => x.Select(p => p.SiteName)
.Select(p => p.SiteId)
.Select(() => regionLocationAlias.City))
.List<object[]>();
Also you might want to have a look at https://github.com/davybrion/NHibernateWorkshop/tree/master/NHibernateWorkshop
There's lots of great examples!
Specifically for your problem, have a look at: https://github.com/davybrion/NHibernateWorkshop/blob/master/NHibernateWorkshop/Querying/QueryOver/Projecting.cs

Categories