I'm following the fantastic example of using NEST and having trouble understanding the mapping logic: Per my understanding, the models hierarchy is:
Package
List<PackageVersion>
List<PackageAuthor>
Each one of the nested types mapped in the example by a call to Nested<T>()
and fluent call to .Name()
.
Here's the Nested<PackageVersion>
example:
.Nested<PackageVersion>(n => n
.Name(p => p.Versions.First())
.AutoMap()
My Question is:
Why call .First()
inside each Name()
call?
Does that mean that only the first item in the list will be indexed? That's not sound like what you want to achieve in the example.
If not, what determines that the whole list should be indexed?
.Name(p => p.Versions.First())
is simply a lambda expression that will resolve to the name to use for the field in the mapping i.e. "versions"
in this case. This is not to be confused with the invocation of a Func<T1, T2>
delegate that will return some value T2
.
In this particular case, the expression could simply be p => p.Versions
, since there is not traversal of the object graph beyond .First()
. Feel free to submit a Pull Request to change :)
EDIT:
To address your comment, the lambda expression here is an Expression Delegate, composed of an Expression tree. That tree can be walked/visited to build up and return a string
to represent that expression. With this example,
MemberExpression
is visited, the member name is retrieved and included in the string
that is returnedMethodCallExpression
is visited, the expression is evaluated to see if it is a LINQ extension method (amongst other methods that the visitor understands), and if it is, the subsequent expressions are visited such that they may contribute to the string
that is returned.Walking/visiting an expression tree is what a LINQ provider such as LINQ to SQL does to compose a SQL statement from an expression. In the case of .Name(p => p.Versions.First())
, the expression is walked to build a string
to use for the field in Elasticsearch. The benefit of using expressions is that they provide some compile time safety in building correct field names and allow you to build longer field names more easily e.g.
.Name(p => p.Versions.First().Dependencies.First().Version)
would build the field "versions.dependencies.version"
. This is useful for querying properties of objects and nested types.