-
Notifications
You must be signed in to change notification settings - Fork 1.3k
CSHARP-4706: Support for $out to Time-series collections #1223
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great, some comments about testing.
tests/MongoDB.Driver.Core.Tests/Core/Operations/AggregateToCollectionOperationTests.cs
Show resolved
Hide resolved
tests/MongoDB.Driver.Core.Tests/Core/Operations/AggregateToCollectionOperationTests.cs
Outdated
Show resolved
Hide resolved
tests/MongoDB.Driver.Core.Tests/Core/Operations/AggregateToCollectionOperationTests.cs
Show resolved
Hide resolved
@@ -330,7 +330,7 @@ private IReadOnlyList<BsonDocument> SimplifyOutStageIfOutputDatabaseIsSameAsInpu | |||
{ | |||
var lastStage = pipeline.Last(); | |||
var lastStageName = lastStage.GetElement(0).Name; | |||
if (lastStageName == "$out" && lastStage["$out"] is BsonDocument outDocument) | |||
if (lastStageName == "$out" && lastStage["$out"] is BsonDocument outDocument && !outDocument.Contains("timeseries")) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we have this tested directly or indirectly somewhere?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is tested indirectly through the Aggregate_out_to_time_series_collection_on_secondary_should_work
test and the AggregateToCollection time series tests. Without this, the simplification of the out stage will just remove the timeseries options resulting in the time series tests failing.
[Fact] | ||
public void Out_with_time_series_options_should_add_expected_stage() | ||
{ | ||
var client = DriverTestConfiguration.Client; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like we just need the collection namespace for rendering.
Maybe we can just mock the collection, and then the test would not be dependent on server?
|
||
var result = PipelineStageDefinitionBuilder.Out(outputCollection, timeSeriesOptions); | ||
|
||
RenderStage(result).Document.Should().Be("{ $out: { db: 'database', coll: 'collection', timeseries: { timeField: 'time', metaField: 'symbol' } } }"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same comment about mocking collection.
private static readonly Feature __aggregateOutOnSecondary = new Feature("AggregateOutOnSecondary", WireVersion.Server50); | ||
private static readonly Feature __aggregateOutTimeSeriesOnSecondary = new Feature("AggregateOutTimeSeriesOnSecondary", WireVersion.Server70); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not sure that we need the secondary feature.
IMongoCollection<TOutput> outputCollection, | ||
TimeSeriesOptions timeSeriesOptions) | ||
{ | ||
Ensure.IsNotNull(pipeline, nameof(pipeline)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should either merge overloads (add timeSeriesOptions = null
parameter) or forbid null here.
I personally would prefer having less overloads for simplicity.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Optional parameters are problematic and I think we should avoid them in our public API. We can use them internally where it makes sense, but not in our public API.
Reason 1: The optional value is inserted into the calling code at compile-time for the calling code. So if you change your default value, but don't recompile the calling code, you'll still use the same value.
Reason 2: Even more insidious is that the C# compiler doesn't enforce consistency among default values. The following is perfectly valid:
var oops1 = new EvilClass();
var oops2 = oops1 as IOops;
Console.WriteLine(oops1.GetValue());
Console.WriteLine(oops2.GetValue());
interface IOops
{
int GetValue(int x = 42);
}
class EvilClass : IOops
{
public int GetValue(int x = 99) => x;
}
The output is:
99
42
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see that we are already doing this elsewhere in our Fluent Aggregate API. Sigh. I guess we can use TimeSeriesOptions timeSeriesOptions = null
here to reduce the number of overloads.
@@ -40,6 +40,7 @@ public class Feature | |||
private static readonly Feature __aggregateLet = new Feature("AggregateLet", WireVersion.Server36); | |||
private static readonly Feature __aggregateMerge = new Feature("AggregateMerge", WireVersion.Server42); | |||
private static readonly Feature __aggregateOut = new Feature("AggregateOut", WireVersion.Server26); | |||
private static readonly Feature __aggregateOutTimeSeries = new Feature("AggregateOutTimeSeries", WireVersion.Server70); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alphabetical order (field and property).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While I don't like optional parameters (see comment below for why), we use them elsewhere. I'm fine with using an optional parameter for timeSeriesOptions
and not adding more overloads. Fix that and some minor comment issues and you're good to go.
/// <typeparam name="TOutput">The type of the output documents.</typeparam> | ||
/// <param name="pipeline">The pipeline.</param> | ||
/// <param name="outputCollection">The output collection.</param> | ||
/// <param name="timeSeriesOptions">The time-series options</param> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
time-series => time series
And add period at end of the param description.
IMongoCollection<TOutput> outputCollection, | ||
TimeSeriesOptions timeSeriesOptions) | ||
{ | ||
Ensure.IsNotNull(pipeline, nameof(pipeline)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Optional parameters are problematic and I think we should avoid them in our public API. We can use them internally where it makes sense, but not in our public API.
Reason 1: The optional value is inserted into the calling code at compile-time for the calling code. So if you change your default value, but don't recompile the calling code, you'll still use the same value.
Reason 2: Even more insidious is that the C# compiler doesn't enforce consistency among default values. The following is perfectly valid:
var oops1 = new EvilClass();
var oops2 = oops1 as IOops;
Console.WriteLine(oops1.GetValue());
Console.WriteLine(oops2.GetValue());
interface IOops
{
int GetValue(int x = 42);
}
class EvilClass : IOops
{
public int GetValue(int x = 99) => x;
}
The output is:
99
42
@@ -1244,17 +1244,36 @@ public static class PipelineStageDefinitionBuilder | |||
/// </summary> | |||
/// <typeparam name="TInput">The type of the input documents.</typeparam> | |||
/// <param name="outputCollection">The output collection.</param> | |||
/// <param name="timeSeriesOptions">The time series options</param> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Period at end of sentence.
IMongoCollection<TOutput> outputCollection, | ||
TimeSeriesOptions timeSeriesOptions) | ||
{ | ||
Ensure.IsNotNull(pipeline, nameof(pipeline)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see that we are already doing this elsewhere in our Fluent Aggregate API. Sigh. I guess we can use TimeSeriesOptions timeSeriesOptions = null
here to reduce the number of overloads.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
No description provided.