Skip to content

Commit a3e416f

Browse files
authored
CSHARP-3400: Implemented support for creating time-series collections. (#559)
1 parent 8339bc0 commit a3e416f

File tree

11 files changed

+703
-30
lines changed

11 files changed

+703
-30
lines changed

src/MongoDB.Driver.Core/Core/Operations/CreateCollectionOperation.cs

Lines changed: 30 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
using MongoDB.Driver.Core.Bindings;
2222
using MongoDB.Driver.Core.Connections;
2323
using MongoDB.Driver.Core.Misc;
24-
using MongoDB.Driver.Core.Servers;
2524
using MongoDB.Driver.Core.WireProtocol.Messages.Encoders;
2625

2726
namespace MongoDB.Driver.Core.Operations
@@ -36,12 +35,14 @@ public class CreateCollectionOperation : IWriteOperation<BsonDocument>
3635
private bool? _capped;
3736
private Collation _collation;
3837
private readonly CollectionNamespace _collectionNamespace;
38+
private TimeSpan? _expireAfter;
3939
private BsonDocument _indexOptionDefaults;
4040
private long? _maxDocuments;
4141
private long? _maxSize;
4242
private readonly MessageEncoderSettings _messageEncoderSettings;
4343
private bool? _noPadding;
4444
private BsonDocument _storageEngine;
45+
private TimeSeriesOptions _timeSeriesOptions;
4546
private bool? _usePowerOf2Sizes;
4647
private DocumentValidationAction? _validationAction;
4748
private DocumentValidationLevel? _validationLevel;
@@ -111,6 +112,18 @@ public CollectionNamespace CollectionNamespace
111112
get { return _collectionNamespace; }
112113
}
113114

115+
/// <summary>
116+
/// Gets or sets the expiration timespan for time-series collections.
117+
/// </summary>
118+
/// <value>
119+
/// The timespan after which to expire documents.
120+
/// </value>
121+
public TimeSpan? ExpireAfter
122+
{
123+
get { return _expireAfter; }
124+
set { _expireAfter = value; }
125+
}
126+
114127
/// <summary>
115128
/// Gets or sets the index option defaults.
116129
/// </summary>
@@ -179,11 +192,23 @@ public BsonDocument StorageEngine
179192
set { _storageEngine = value; }
180193
}
181194

195+
/// <summary>
196+
/// Gets or sets the <see cref="TimeSeriesOptions"/> to use when creating a time series collection.
197+
/// </summary>
198+
/// <value>
199+
/// The time series options.
200+
/// </value>
201+
public TimeSeriesOptions TimeSeriesOptions
202+
{
203+
get { return _timeSeriesOptions; }
204+
set { _timeSeriesOptions = value; }
205+
}
206+
182207
/// <summary>
183208
/// Gets or sets a value indicating whether the collection should use power of 2 sizes.
184209
/// </summary>
185210
/// <value>
186-
/// A value indicating whether the collection should use power of 2 sizes..
211+
/// A value indicating whether the collection should use power of 2 sizes.
187212
/// </value>
188213
public bool? UsePowerOf2Sizes
189214
{
@@ -261,7 +286,9 @@ internal BsonDocument CreateCommand(ICoreSessionHandle session, ConnectionDescri
261286
{ "validationAction", () => _validationAction.Value.ToString().ToLowerInvariant(), _validationAction.HasValue },
262287
{ "validationLevel", () => _validationLevel.Value.ToString().ToLowerInvariant(), _validationLevel.HasValue },
263288
{ "collation", () => _collation.ToBsonDocument(), _collation != null },
264-
{ "writeConcern", writeConcern, writeConcern != null }
289+
{ "writeConcern", writeConcern, writeConcern != null },
290+
{ "expireAfterSeconds", () => _expireAfter.Value.TotalSeconds, _expireAfter.HasValue },
291+
{ "timeseries", () => _timeSeriesOptions.ToBsonDocument(), _timeSeriesOptions != null }
265292
};
266293
}
267294

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/* Copyright 2021-present MongoDB Inc.
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
namespace MongoDB.Driver
17+
{
18+
/// <summary>
19+
/// Specifies the granularity of time series collection bucketing.
20+
/// </summary>
21+
public enum TimeSeriesGranularity
22+
{
23+
/// <summary>
24+
/// Seconds.
25+
/// </summary>
26+
Seconds,
27+
/// <summary>
28+
/// Minutes.
29+
/// </summary>
30+
Minutes,
31+
/// <summary>
32+
/// Hours.
33+
/// </summary>
34+
Hours
35+
}
36+
}
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/* Copyright 2021-present MongoDB Inc.
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
using MongoDB.Bson;
17+
using MongoDB.Driver.Core.Misc;
18+
19+
namespace MongoDB.Driver
20+
{
21+
/// <summary>
22+
/// Defines the time series options to use when creating a time-series collection.
23+
/// </summary>
24+
public class TimeSeriesOptions
25+
{
26+
private readonly TimeSeriesGranularity? _granularity;
27+
private readonly string _metaField;
28+
private readonly string _timeField;
29+
30+
/// <summary>
31+
/// Initializes a new instance of the <see cref="TimeSeriesOptions"/> class.
32+
/// </summary>
33+
/// <param name="timeField">The name of the top-level field to be used for time.</param>
34+
/// <param name="metaField">The name of the top-level field describing the series upon which related data will be grouped.</param>
35+
/// <param name="granularity">The <see cref="TimeSeriesGranularity"/> for the time series.</param>
36+
public TimeSeriesOptions(string timeField, Optional<string> metaField = default, Optional<TimeSeriesGranularity?> granularity = default)
37+
{
38+
_timeField = Ensure.IsNotNullOrEmpty(timeField, nameof(timeField));
39+
_metaField = metaField.WithDefault(null);
40+
_granularity = granularity.WithDefault(null);
41+
}
42+
43+
/// <summary>
44+
/// The coarse granularity of time-series data.
45+
/// </summary>
46+
public TimeSeriesGranularity? Granularity => _granularity;
47+
48+
/// <summary>
49+
/// The name of the field which contains metadata in each time-series document.
50+
/// </summary>
51+
public string MetaField => _metaField;
52+
53+
/// <summary>
54+
/// The name of the field which contains the date and time in each time-series document.
55+
/// </summary>
56+
public string TimeField => _timeField;
57+
58+
/// <summary>
59+
/// The BSON representation of the time-series options.
60+
/// </summary>
61+
/// <returns>A BsonDocument.</returns>
62+
public BsonDocument ToBsonDocument()
63+
{
64+
return new BsonDocument
65+
{
66+
{ "timeField", _timeField },
67+
{ "metaField", _metaField, _metaField != null },
68+
{ "granularity", () => _granularity.Value.ToString().ToLowerInvariant(), _granularity.HasValue }
69+
};
70+
}
71+
}
72+
}

src/MongoDB.Driver/CreateCollectionOptions.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,13 @@ public class CreateCollectionOptions
2828
private bool? _autoIndexId;
2929
private bool? _capped;
3030
private Collation _collation;
31+
private TimeSpan? _expireAfter;
3132
private IndexOptionDefaults _indexOptionDefaults;
3233
private long? _maxDocuments;
3334
private long? _maxSize;
3435
private bool? _noPadding;
3536
private BsonDocument _storageEngine;
37+
private TimeSeriesOptions _timeSeriesOptions;
3638
private bool? _usePowerOf2Sizes;
3739
private IBsonSerializerRegistry _serializerRegistry;
3840
private DocumentValidationAction? _validationAction;
@@ -67,6 +69,16 @@ public bool? Capped
6769
set { _capped = value; }
6870
}
6971

72+
73+
/// <summary>
74+
/// Gets or sets a timespan indicating how long documents in a time series collection should be retained.
75+
/// </summary>
76+
public TimeSpan? ExpireAfter
77+
{
78+
get { return _expireAfter; }
79+
set { _expireAfter = value; }
80+
}
81+
7082
/// <summary>
7183
/// Gets or sets the index option defaults.
7284
/// </summary>
@@ -124,6 +136,15 @@ public BsonDocument StorageEngine
124136
set { _storageEngine = value; }
125137
}
126138

139+
/// <summary>
140+
/// Gets or sets the <see cref="TimeSeriesOptions"/> to use when creating a time series collection.
141+
/// </summary>
142+
public TimeSeriesOptions TimeSeriesOptions
143+
{
144+
get { return _timeSeriesOptions; }
145+
set { _timeSeriesOptions = value; }
146+
}
147+
127148
/// <summary>
128149
/// Gets or sets a value indicating whether to use power of 2 sizes.
129150
/// </summary>
@@ -186,12 +207,14 @@ internal static CreateCollectionOptions<TDocument> CoercedFrom(CreateCollectionO
186207
AutoIndexId = options.AutoIndexId,
187208
Capped = options.Capped,
188209
Collation = options.Collation,
210+
ExpireAfter = options.ExpireAfter,
189211
IndexOptionDefaults = options.IndexOptionDefaults,
190212
MaxDocuments = options.MaxDocuments,
191213
MaxSize = options.MaxSize,
192214
NoPadding = options.NoPadding,
193215
SerializerRegistry = options.SerializerRegistry,
194216
StorageEngine = options.StorageEngine,
217+
TimeSeriesOptions = options.TimeSeriesOptions,
195218
UsePowerOf2Sizes = options.UsePowerOf2Sizes,
196219
ValidationAction = options.ValidationAction,
197220
ValidationLevel = options.ValidationLevel

src/MongoDB.Driver/MongoDatabaseImpl.cs

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -626,27 +626,6 @@ private Task CreateCollectionHelperAsync<TDocument>(IClientSessionHandle session
626626
return ExecuteWriteOperationAsync(session, operation, cancellationToken);
627627
}
628628

629-
private CreateCollectionOperation CreateCreateCollectionOperation(string name, CreateCollectionOptions options)
630-
{
631-
options = options ?? new CreateCollectionOptions();
632-
var messageEncoderSettings = GetMessageEncoderSettings();
633-
634-
#pragma warning disable 618
635-
return new CreateCollectionOperation(new CollectionNamespace(_databaseNamespace, name), messageEncoderSettings)
636-
{
637-
AutoIndexId = options.AutoIndexId,
638-
Collation = options.Collation,
639-
Capped = options.Capped,
640-
MaxDocuments = options.MaxDocuments,
641-
MaxSize = options.MaxSize,
642-
NoPadding = options.NoPadding,
643-
StorageEngine = options.StorageEngine,
644-
UsePowerOf2Sizes = options.UsePowerOf2Sizes,
645-
WriteConcern = _settings.WriteConcern
646-
};
647-
#pragma warning restore
648-
}
649-
650629
private CreateCollectionOperation CreateCreateCollectionOperation<TDocument>(string name, CreateCollectionOptions<TDocument> options)
651630
{
652631
var messageEncoderSettings = GetMessageEncoderSettings();
@@ -664,11 +643,13 @@ private CreateCollectionOperation CreateCreateCollectionOperation<TDocument>(str
664643
AutoIndexId = options.AutoIndexId,
665644
Capped = options.Capped,
666645
Collation = options.Collation,
646+
ExpireAfter = options.ExpireAfter,
667647
IndexOptionDefaults = options.IndexOptionDefaults?.ToBsonDocument(),
668648
MaxDocuments = options.MaxDocuments,
669649
MaxSize = options.MaxSize,
670650
NoPadding = options.NoPadding,
671651
StorageEngine = options.StorageEngine,
652+
TimeSeriesOptions = options.TimeSeriesOptions,
672653
UsePowerOf2Sizes = options.UsePowerOf2Sizes,
673654
ValidationAction = options.ValidationAction,
674655
ValidationLevel = options.ValidationLevel,
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/* Copyright 2021-present MongoDB Inc.
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
using System;
17+
using FluentAssertions;
18+
using Xunit;
19+
20+
namespace MongoDB.Driver
21+
{
22+
public class TimeSeriesOptionsTests
23+
{
24+
[Fact]
25+
public void constructor_with_timeField_should_initialize_instance()
26+
{
27+
const string timeField = "time";
28+
var result = new TimeSeriesOptions(timeField);
29+
30+
result.TimeField.Should().Be(timeField);
31+
result.MetaField.Should().BeNull();
32+
result.Granularity.Should().BeNull();
33+
}
34+
35+
[Fact]
36+
public void constructor_with_null_timeField_should_throw()
37+
{
38+
const string timeField = null;
39+
var exception = Record.Exception(() => new TimeSeriesOptions(timeField));
40+
exception.Should().BeOfType<ArgumentNullException>();
41+
}
42+
43+
[Fact]
44+
public void constructor_with_empty_string_timeField_should_throw()
45+
{
46+
const string timeField = "";
47+
var exception = Record.Exception(() => new TimeSeriesOptions(timeField));
48+
exception.Should().BeOfType<ArgumentException>();
49+
}
50+
51+
[Fact]
52+
public void constructor_with_all_parameters_should_initialize_instance()
53+
{
54+
const string timeField = "time";
55+
const string metaField = "meta";
56+
const TimeSeriesGranularity granularity = TimeSeriesGranularity.Hours;
57+
58+
var result = new TimeSeriesOptions(timeField, metaField, granularity);
59+
60+
result.TimeField.Should().Be(timeField);
61+
result.MetaField.Should().Be(metaField);
62+
result.Granularity.Should().Be(granularity);
63+
}
64+
}
65+
}

0 commit comments

Comments
 (0)