diff --git a/src/Nest/DSL/Aggregations/AggregationDescriptor.cs b/src/Nest/DSL/Aggregations/AggregationDescriptor.cs index 7509601eec0..8cc8c4c9722 100644 --- a/src/Nest/DSL/Aggregations/AggregationDescriptor.cs +++ b/src/Nest/DSL/Aggregations/AggregationDescriptor.cs @@ -60,6 +60,9 @@ public interface IAggregationContainer [JsonProperty("nested")] INestedAggregator Nested { get; set; } + [JsonProperty("reverse_nested")] + IReverseNestedAggregator ReverseNested { get; set; } + [JsonProperty("range")] IRangeAggregator Range { get; set; } @@ -102,6 +105,7 @@ public class AggregationContainer : IAggregationContainer private ICardinalityAggregator _cardinality; private IMissingAggregator _missing; private INestedAggregator _nested; + private IReverseNestedAggregator _reverseNested; private IRangeAggregator _range; private ITermsAggregator _terms; private ISignificantTermsAggregator _significantTerms; @@ -193,6 +197,12 @@ public INestedAggregator Nested set { _nested = value; } } + public IReverseNestedAggregator ReverseNested + { + get { return _reverseNested; } + set { _reverseNested = value; } + } + public IRangeAggregator Range { get { return _range; } @@ -264,6 +274,8 @@ public class AggregationDescriptor : IAggregationContainer IMissingAggregator IAggregationContainer.Missing { get; set; } INestedAggregator IAggregationContainer.Nested { get; set; } + + IReverseNestedAggregator IAggregationContainer.ReverseNested { get; set; } IRangeAggregator IAggregationContainer.Range { get; set; } @@ -381,6 +393,11 @@ public AggregationDescriptor Nested(string name, Func a.Nested = d); } + public AggregationDescriptor ReverseNested(string name, Func, ReverseNestedAggregationDescriptor> selector) + { + return _SetInnerAggregation(name, selector, (a, d) => a.ReverseNested = d); + } + public AggregationDescriptor Range(string name, Func, RangeAggregationDescriptor> selector) { return _SetInnerAggregation(name, selector, (a, d) => a.Range = d); diff --git a/src/Nest/DSL/Aggregations/ReverseNestedAggregationDescriptor.cs b/src/Nest/DSL/Aggregations/ReverseNestedAggregationDescriptor.cs new file mode 100644 index 00000000000..c9cbf4f3cec --- /dev/null +++ b/src/Nest/DSL/Aggregations/ReverseNestedAggregationDescriptor.cs @@ -0,0 +1,44 @@ +using Nest.Resolvers.Converters; +using Newtonsoft.Json; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Linq.Expressions; +using System.Text; + +namespace Nest +{ + [JsonObject(MemberSerialization = MemberSerialization.OptIn)] + [JsonConverter(typeof(ReadAsTypeConverter))] + public interface IReverseNestedAggregator : IBucketAggregator + { + [JsonProperty("path")] + PropertyPathMarker Path { get; set; } + } + + public class ReverseNestedAggregator : BucketAggregator, IReverseNestedAggregator + { + [JsonProperty("path")] + public PropertyPathMarker Path { get; set; } + } + + public class ReverseNestedAggregationDescriptor + : BucketAggregationBaseDescriptor, T>, IReverseNestedAggregator + where T : class + { + IReverseNestedAggregator Self { get { return this; } } + PropertyPathMarker IReverseNestedAggregator.Path { get; set; } + + public ReverseNestedAggregationDescriptor Path(string path) + { + this.Self.Path = path; + return this; + } + + public ReverseNestedAggregationDescriptor Path(Expression> path) + { + this.Self.Path = path; + return this; + } + } +} diff --git a/src/Nest/Domain/Aggregations/AggregationsHelper.cs b/src/Nest/Domain/Aggregations/AggregationsHelper.cs index 76d2f292e91..5c3a2b681bf 100644 --- a/src/Nest/Domain/Aggregations/AggregationsHelper.cs +++ b/src/Nest/Domain/Aggregations/AggregationsHelper.cs @@ -101,6 +101,11 @@ public SingleBucket Nested(string key) return this.TryGet(key); } + public SingleBucket ReverseNested(string key) + { + return this.TryGet(key); + } + public BucketWithDocCount SignificantTerms(string key) { var bucket = this.TryGet(key); diff --git a/src/Nest/Nest.csproj b/src/Nest/Nest.csproj index f7cc98914b8..50213d86174 100644 --- a/src/Nest/Nest.csproj +++ b/src/Nest/Nest.csproj @@ -212,6 +212,7 @@ + diff --git a/src/Tests/Nest.Tests.Integration/Aggregations/NestedBucketAggregationTests.cs b/src/Tests/Nest.Tests.Integration/Aggregations/NestedBucketAggregationTests.cs index dbbf06fbc4f..eccdeb42712 100644 --- a/src/Tests/Nest.Tests.Integration/Aggregations/NestedBucketAggregationTests.cs +++ b/src/Tests/Nest.Tests.Integration/Aggregations/NestedBucketAggregationTests.cs @@ -45,5 +45,44 @@ public void Terms() .And.BeGreaterOrEqualTo(18); } + [Test] + public void ReverseNested() + { + var results = this.Client.Search(s => s + .Size(0) + .Aggregations(a => a + .Nested("contributors", n => n + .Path(p => p.Contributors) + .Aggregations(t => t + .Terms("ages", m => m + .Field(p => p.Contributors.First().Age) + .Aggregations(aa => aa + .ReverseNested("contributor_to_project", rn => rn + .Aggregations(aaa => aaa + .Terms("countries_per_age", tt => tt + .Field(p => p.Country) + ) + ) + ) + ) + ) + ) + ) + ) + ); + + results.IsValid.Should().BeTrue(); + var contributors = results.Aggs.Nested("contributors"); + var ages = contributors.Aggregations["ages"] as Bucket; + + foreach (var item in ages.Items) + { + var age = item as KeyItem; + age.Key.Should().NotBeNullOrWhiteSpace(); + var contributorToProject = age.Aggregations["contributor_to_project"] as SingleBucket; + var countriesPerAge = contributorToProject.Terms("countries_per_age"); + countriesPerAge.Items.Count().Should().BeGreaterThan(0); + } + } } } \ No newline at end of file