diff --git a/src/Nest/Aggregations/Bucket/Composite/CompositeAggregationSource.cs b/src/Nest/Aggregations/Bucket/Composite/CompositeAggregationSource.cs index a7ea04f992f..9aa80bd06a7 100644 --- a/src/Nest/Aggregations/Bucket/Composite/CompositeAggregationSource.cs +++ b/src/Nest/Aggregations/Bucket/Composite/CompositeAggregationSource.cs @@ -26,6 +26,14 @@ public interface ICompositeAggregationSource [JsonProperty("missing_bucket")] bool? MissingBucket { get; set; } + + /// + /// Allows an explicit value to be set when one is missing for the field. + /// + [Obsolete("Will be removed in Elasticsearch 7.x. Use MissingBucket")] + [JsonProperty("missing")] + object Missing { get; set; } + /// /// The name of the source /// @@ -60,6 +68,10 @@ protected CompositeAggregationSourceBase(string name) => /// public bool? MissingBucket { get; set; } + /// + [Obsolete("Will be removed in Elasticsearch 7.x. Use MissingBucket")] + public object Missing { get; set; } + /// public SortOrder? Order { get; set; } @@ -114,7 +126,8 @@ protected CompositeAggregationSourceDescriptorBase(string name, string sourceTyp Field ICompositeAggregationSource.Field { get; set; } bool? ICompositeAggregationSource.MissingBucket { get; set; } - + [Obsolete("Will be removed in Elasticsearch 7.x. Use MissingBucket")] + object ICompositeAggregationSource.Missing { get; set; } string ICompositeAggregationSource.Name { get; set; } SortOrder? ICompositeAggregationSource.Order { get; set; } string ICompositeAggregationSource.SourceType => _sourceType; @@ -130,6 +143,10 @@ protected CompositeAggregationSourceDescriptorBase(string name, string sourceTyp /// public TDescriptor MissingBucket(bool? includeMissing = true) => Assign(a => a.MissingBucket = includeMissing); + + /// + [Obsolete("Will be removed in Elasticsearch 7.x. Use MissingBucket")] + public TDescriptor Missing(object missingObject) => Assign(a => a.Missing = missingObject); } internal class CompositeAggregationSourceConverter : ReserializeJsonConverter diff --git a/src/Tests/Tests/Aggregations/Bucket/Composite/CompositeAggregationUsageTests.cs b/src/Tests/Tests/Aggregations/Bucket/Composite/CompositeAggregationUsageTests.cs index 54b6413619b..2f422f551dc 100644 --- a/src/Tests/Tests/Aggregations/Bucket/Composite/CompositeAggregationUsageTests.cs +++ b/src/Tests/Tests/Aggregations/Bucket/Composite/CompositeAggregationUsageTests.cs @@ -319,6 +319,130 @@ protected override void ExpectResponse(ISearchResponse response) } } + // hide +#pragma warning disable 618 + [SkipVersion("<6.4.0", "Missing added to Composite Aggregation Elasticsearch 6.4.0+")] + public class CompositeAggregationMissingUsageTests : ProjectsOnlyAggregationUsageTestBase + { + public CompositeAggregationMissingUsageTests(ReadOnlyCluster i, EndpointUsage usage) : base(i, usage) { } + + protected override object AggregationJson => new + { + my_buckets = new + { + composite = new + { + sources = new object[] + { + new + { + branches = new + { + terms = new + { + field = "branches.keyword", + order = "asc", + missing = "missing_branch" + } + } + }, + } + }, + aggs = new + { + project_tags = new + { + nested = new { path = "tags" }, + aggs = new + { + tags = new { terms = new { field = "tags.name" } } + } + } + } + } + }; + + protected override Func, IAggregationContainer> FluentAggs => a => a + .Composite("my_buckets", date => date + .Sources(s => s + .Terms("branches", t => t + .Field(f => f.Branches.Suffix("keyword")) + + .Missing("missing_branch") + .Order(SortOrder.Ascending) + ) + ) + .Aggregations(childAggs => childAggs + .Nested("project_tags", n => n + .Path(p => p.Tags) + .Aggregations(nestedAggs => nestedAggs + .Terms("tags", avg => avg.Field(p => p.Tags.First().Name)) + ) + ) + ) + ); + + protected override AggregationDictionary InitializerAggs => + new CompositeAggregation("my_buckets") + { + Sources = new List + { + new TermsCompositeAggregationSource("branches") + { + Field = Field(f => f.Branches.Suffix("keyword")), + Missing = "missing_branch", + Order = SortOrder.Ascending + } + }, + Aggregations = new NestedAggregation("project_tags") + { + Path = Field(p => p.Tags), + Aggregations = new TermsAggregation("tags") + { + Field = Field(p => p.Tags.First().Name) + } + } + }; + + protected override void ExpectResponse(ISearchResponse response) + { + response.ShouldBeValid(); + + var composite = response.Aggregations.Composite("my_buckets"); + composite.Should().NotBeNull(); + composite.Buckets.Should().NotBeNullOrEmpty(); + composite.AfterKey.Should().NotBeNull(); + + if (TestConfiguration.Instance.InRange(">=6.3.0")) + composite.AfterKey.Should().HaveCount(1).And.ContainKeys("branches"); + + var i = 0; + var seenMissingBranches = false; + foreach (var item in composite.Buckets) + { + var key = item.Key; + key.Should().NotBeNull(); + + key.TryGetValue("branches", out string branches).Should().BeTrue("expected to find 'branches' in composite bucket"); + branches.Should().NotBeNullOrEmpty(); + if (branches == "missing_branch") + { + seenMissingBranches = true; + } + + var nested = item.Nested("project_tags"); + nested.Should().NotBeNull(); + + var nestedTerms = nested.Terms("tags"); + nestedTerms.Buckets.Count.Should().BeGreaterThan(0); + i++; + } + + seenMissingBranches.Should().BeTrue(); + } + } +#pragma warning restore 618 + //hide [SkipVersion("<6.3.0", "Date histogram source only supports format starting from Elasticsearch 6.3.0+")] public class DateFormatCompositeAggregationUsageTests : ProjectsOnlyAggregationUsageTestBase