Elasticsearch .net v8 and operator

Hi, just started porting our ES facing code from NEST to the new V8 client. I am facing some issues that I would like to get some input on.

In NEST I am able to use the AND operator to "join" multiple QueryContainers like this:

        public class TrackingEvent
        {
           public string SessionKey { set; get; }
           public string Email { set; get; }
        }

        private QueryContainer CreateQueryContainer(string email, string sessionKey)
        {

            QueryContainerDescriptor<TrackingEvent> queryContainerDescriptor = new QueryContainerDescriptor<TrackingEvent>();
            QueryContainer queryContainer = new QueryContainer();

            if (!string.IsNullOrEmpty(sessionKey))
            {
                var queryDescriptor = new TermQueryDescriptor<TrackingEvent>();
                queryDescriptor.Field(x => x.SessionKey).Value(sessionKey);
                queryContainer &= queryContainerDescriptor.Term(x => queryDescriptor);
            }

            if (!string.IsNullOrEmpty(email))
            {
                var queryDescriptor = new TermQueryDescriptor<TrackingEvent>();
                queryDescriptor.Field(x => x.Email).Value(email);
                queryContainer &= queryContainerDescriptor.Term(x => queryDescriptor);
            }

            return queryContainer;
        }

I have a hard time finding out how I can achieve the same thing in the V8 client.

Any help and guidance is highly appreciated here.

Thanks!

Hi @Odd_Erik_Gronberg,

these operators are shortcuts for a BoolQuery (either should or must). The QueryContainerDescriptor is now called QueryDescriptor and the corresponding non-fluent class is just Query. The latter one still supports these operators, but for the descriptors they are not available at the moment.

You could either change your code to use Query instead of the descriptors, or probably even better (based on the code snippet you posted), keep building the individual queries for sessionKey and email, store then in a list and create the "container" in the very end using a single Query.Bool(...Must(queryList)).

Thanks @flobernd !

The query approach would work but we will miss the strongly typed field name we get through the generic descriptors. I found a workaround for this using the Infer.Field for the corresponding class instead, but preferably we would continue to use the fluent descriptors.

I am not quite able to figure out how to implement the second approach you suggest here. Are you referring to the usage of:

	public BoolQueryDescriptor<TDocument> Must(params Action<Elastic.Clients.Elasticsearch.QueryDsl.QueryDescriptor<TDocument>>[] configure)
	{
		MustValue = null;
		MustDescriptor = null;
		MustDescriptorAction = null;
		MustDescriptorActions = configure;
		return Self;
	}

when passing a query list here?

Thanks!

Hi @Odd_Erik_Gronberg,

at the moment it's kinda hard to mix fluent and object syntax.

Yes! The trick is to maintain a list of Action<QueryDescriptor<T>>> instead of just a list of QueryDescriptor<T>. Using this approach you can dynamically add or remove actions from the list, before crafting the final query descriptor that combines the sub-queries. Must is equivalent to && and Should is equivalent to ||.

var actions = new List<Action<QueryDescriptor<Person>>>()
{
	x => x.Term(x => x.Field(p => p.FirstName)),
	x => x.Term(x => x.Field(p => p.Email)),
};

var q = new QueryDescriptor<Person>().Bool(x => x.Must(actions.ToArray()));

Nice! Thanks for your help @flobernd !

1 Like