diff --git a/src/MongoDB.Driver.Core/Core/Misc/Feature.cs b/src/MongoDB.Driver.Core/Core/Misc/Feature.cs
index bb01704775d..0e33f526338 100644
--- a/src/MongoDB.Driver.Core/Core/Misc/Feature.cs
+++ b/src/MongoDB.Driver.Core/Core/Misc/Feature.cs
@@ -41,6 +41,7 @@ public class Feature
private static readonly Feature __aggregateMerge = new Feature("AggregateMerge", WireVersion.Server42);
private static readonly Feature __aggregateOut = new Feature("AggregateOut", WireVersion.Server26);
private static readonly Feature __aggregateOutOnSecondary = new Feature("AggregateOutOnSecondary", WireVersion.Server50);
+ private static readonly Feature __aggregateOutTimeSeries = new Feature("AggregateOutTimeSeries", WireVersion.Server70);
private static readonly Feature __aggregateOutToDifferentDatabase = new Feature("AggregateOutToDifferentDatabase", WireVersion.Server44);
private static readonly Feature __aggregateToString = new Feature("AggregateToString", WireVersion.Server40);
private static readonly Feature __aggregateUnionWith = new Feature("AggregateUnionWith", WireVersion.Server44);
@@ -237,10 +238,15 @@ public class Feature
public static Feature AggregateOut => __aggregateOut;
///
- /// Gets the aggregate out on secondary feature,
+ /// Gets the aggregate out on secondary feature.
///
public static Feature AggregateOutOnSecondary => __aggregateOutOnSecondary;
+ ///
+ /// Gets the aggregate out to time series feature.
+ ///
+ public static Feature AggregateOutTimeSeries => __aggregateOutTimeSeries;
+
///
/// Gets the aggregate out to a different database feature.
///
diff --git a/src/MongoDB.Driver.Core/Core/Operations/AggregateToCollectionOperation.cs b/src/MongoDB.Driver.Core/Core/Operations/AggregateToCollectionOperation.cs
index ca63d77f0ce..43871ae08b8 100644
--- a/src/MongoDB.Driver.Core/Core/Operations/AggregateToCollectionOperation.cs
+++ b/src/MongoDB.Driver.Core/Core/Operations/AggregateToCollectionOperation.cs
@@ -330,7 +330,7 @@ private IReadOnlyList 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"))
{
if (outDocument.TryGetValue("db", out var db) && db.IsString &&
outDocument.TryGetValue("coll", out var coll) && coll.IsString)
diff --git a/src/MongoDB.Driver/AggregateFluent.cs b/src/MongoDB.Driver/AggregateFluent.cs
index 75b53d2f1a2..b48ece1f8d4 100644
--- a/src/MongoDB.Driver/AggregateFluent.cs
+++ b/src/MongoDB.Driver/AggregateFluent.cs
@@ -210,6 +210,20 @@ public override IAsyncCursor Out(string collectionName, CancellationTok
return Out(outputCollection, cancellationToken);
}
+ public override IAsyncCursor Out(IMongoCollection outputCollection, TimeSeriesOptions timeSeriesOptions, CancellationToken cancellationToken)
+ {
+ Ensure.IsNotNull(outputCollection, nameof(outputCollection));
+ var aggregate = WithPipeline(_pipeline.Out(outputCollection, timeSeriesOptions));
+ return aggregate.ToCursor(cancellationToken);
+ }
+
+ public override IAsyncCursor Out(string collectionName, TimeSeriesOptions timeSeriesOptions, CancellationToken cancellationToken)
+ {
+ Ensure.IsNotNull(collectionName, nameof(collectionName));
+ var outputCollection = Database.GetCollection(collectionName);
+ return Out(outputCollection, timeSeriesOptions, cancellationToken);
+ }
+
public override Task> OutAsync(IMongoCollection outputCollection, CancellationToken cancellationToken)
{
Ensure.IsNotNull(outputCollection, nameof(outputCollection));
@@ -224,6 +238,20 @@ public override Task> OutAsync(string collectionName, Canc
return OutAsync(outputCollection, cancellationToken);
}
+ public override Task> OutAsync(IMongoCollection outputCollection, TimeSeriesOptions timeSeriesOptions, CancellationToken cancellationToken)
+ {
+ Ensure.IsNotNull(outputCollection, nameof(outputCollection));
+ var aggregate = WithPipeline(_pipeline.Out(outputCollection, timeSeriesOptions));
+ return aggregate.ToCursorAsync(cancellationToken);
+ }
+
+ public override Task> OutAsync(string collectionName, TimeSeriesOptions timeSeriesOptions, CancellationToken cancellationToken)
+ {
+ Ensure.IsNotNull(collectionName, nameof(collectionName));
+ var outputCollection = Database.GetCollection(collectionName);
+ return OutAsync(outputCollection, timeSeriesOptions, cancellationToken);
+ }
+
public override IAggregateFluent Project(ProjectionDefinition projection)
{
return WithPipeline(_pipeline.Project(projection));
diff --git a/src/MongoDB.Driver/AggregateFluentBase.cs b/src/MongoDB.Driver/AggregateFluentBase.cs
index b0619e4e633..4f26aecee87 100644
--- a/src/MongoDB.Driver/AggregateFluentBase.cs
+++ b/src/MongoDB.Driver/AggregateFluentBase.cs
@@ -192,6 +192,18 @@ public virtual IAsyncCursor Out(string collectionName, CancellationToke
throw new NotImplementedException();
}
+ ///
+ public virtual IAsyncCursor Out(IMongoCollection outputCollection, TimeSeriesOptions timeSeriesOptions, CancellationToken cancellationToken)
+ {
+ throw new NotImplementedException();
+ }
+
+ ///
+ public virtual IAsyncCursor Out(string collectionName, TimeSeriesOptions timeSeriesOptions, CancellationToken cancellationToken)
+ {
+ throw new NotImplementedException();
+ }
+
///
public virtual Task> OutAsync(IMongoCollection outputCollection, CancellationToken cancellationToken)
{
@@ -201,6 +213,15 @@ public virtual Task> OutAsync(IMongoCollection ou
///
public abstract Task> OutAsync(string collectionName, CancellationToken cancellationToken);
+ ///
+ public virtual Task> OutAsync(IMongoCollection outputCollection, TimeSeriesOptions timeSeriesOptions, CancellationToken cancellationToken)
+ {
+ throw new NotImplementedException();
+ }
+
+ ///
+ public abstract Task> OutAsync(string collectionName, TimeSeriesOptions timeSeriesOptions, CancellationToken cancellationToken);
+
///
public abstract IAggregateFluent Project(ProjectionDefinition projection);
diff --git a/src/MongoDB.Driver/IAggregateFluent.cs b/src/MongoDB.Driver/IAggregateFluent.cs
index 8ad1ba38a0f..c2547b34506 100644
--- a/src/MongoDB.Driver/IAggregateFluent.cs
+++ b/src/MongoDB.Driver/IAggregateFluent.cs
@@ -303,6 +303,24 @@ IAggregateFluent LookupA cursor.
IAsyncCursor Out(string collectionName, CancellationToken cancellationToken = default(CancellationToken));
+ ///
+ /// Appends an out stage to the pipeline and executes it, and then returns a cursor to read the contents of the output collection.
+ ///
+ /// The output collection.
+ /// The time series options.
+ /// The cancellation token.
+ /// A cursor.
+ IAsyncCursor Out(IMongoCollection outputCollection, TimeSeriesOptions timeSeriesOptions, CancellationToken cancellationToken = default(CancellationToken));
+
+ ///
+ /// Appends an out stage to the pipeline and executes it, and then returns a cursor to read the contents of the output collection.
+ ///
+ /// Name of the collection.
+ /// The time series options.
+ /// The cancellation token.
+ /// A cursor.
+ IAsyncCursor Out(string collectionName, TimeSeriesOptions timeSeriesOptions, CancellationToken cancellationToken = default(CancellationToken));
+
///
/// Appends an out stage to the pipeline and executes it, and then returns a cursor to read the contents of the output collection.
///
@@ -319,6 +337,24 @@ IAggregateFluent LookupA Task whose result is a cursor.
Task> OutAsync(string collectionName, CancellationToken cancellationToken = default(CancellationToken));
+ ///
+ /// Appends an out stage to the pipeline and executes it, and then returns a cursor to read the contents of the output collection.
+ ///
+ /// The output collection.
+ /// The time series options.
+ /// The cancellation token.
+ /// A Task whose result is a cursor.
+ Task> OutAsync(IMongoCollection outputCollection, TimeSeriesOptions timeSeriesOptions, CancellationToken cancellationToken = default(CancellationToken));
+
+ ///
+ /// Appends an out stage to the pipeline and executes it, and then returns a cursor to read the contents of the output collection.
+ ///
+ /// Name of the collection.
+ /// The time series options.
+ /// The cancellation token.
+ /// A Task whose result is a cursor.
+ Task> OutAsync(string collectionName, TimeSeriesOptions timeSeriesOptions, CancellationToken cancellationToken = default(CancellationToken));
+
///
/// Appends a project stage to the pipeline.
///
diff --git a/src/MongoDB.Driver/PipelineDefinitionBuilder.cs b/src/MongoDB.Driver/PipelineDefinitionBuilder.cs
index dd358e07558..4d89ad32c54 100644
--- a/src/MongoDB.Driver/PipelineDefinitionBuilder.cs
+++ b/src/MongoDB.Driver/PipelineDefinitionBuilder.cs
@@ -960,14 +960,16 @@ public static PipelineDefinition MergeThe type of the output documents.
/// The pipeline.
/// The output collection.
+ /// The time series options.
/// A new pipeline with an additional stage.
///
public static PipelineDefinition Out(
this PipelineDefinition pipeline,
- IMongoCollection outputCollection)
+ IMongoCollection outputCollection,
+ TimeSeriesOptions timeSeriesOptions = null)
{
Ensure.IsNotNull(pipeline, nameof(pipeline));
- return pipeline.AppendStage(PipelineStageDefinitionBuilder.Out(outputCollection));
+ return pipeline.AppendStage(PipelineStageDefinitionBuilder.Out(outputCollection, timeSeriesOptions));
}
///
@@ -1111,7 +1113,7 @@ public static PipelineDefinition ReplaceWith
///
/// Flag that specifies whether to return a detailed breakdown
- /// of the score for each document in the result.
+ /// of the score for each document in the result.
///
/// A new pipeline with an additional stage.
public static PipelineDefinition Search(
diff --git a/src/MongoDB.Driver/PipelineStageDefinitionBuilder.cs b/src/MongoDB.Driver/PipelineStageDefinitionBuilder.cs
index 771c3efdc13..e88172bd0b9 100644
--- a/src/MongoDB.Driver/PipelineStageDefinitionBuilder.cs
+++ b/src/MongoDB.Driver/PipelineStageDefinitionBuilder.cs
@@ -1244,14 +1244,21 @@ public static PipelineStageDefinition OfType(
///
/// The type of the input documents.
/// The output collection.
+ /// The time series options.
/// The stage.
public static PipelineStageDefinition Out(
- IMongoCollection outputCollection)
+ IMongoCollection outputCollection,
+ TimeSeriesOptions timeSeriesOptions = null)
{
Ensure.IsNotNull(outputCollection, nameof(outputCollection));
var outputDatabaseName = outputCollection.Database.DatabaseNamespace.DatabaseName;
var outputCollectionName = outputCollection.CollectionNamespace.CollectionName;
- var outDocument = new BsonDocument { { "db", outputDatabaseName }, { "coll", outputCollectionName } };
+ var outDocument = new BsonDocument
+ {
+ { "db", outputDatabaseName },
+ { "coll", outputCollectionName },
+ { "timeseries", () => timeSeriesOptions.ToBsonDocument(), timeSeriesOptions != null}
+ };
return new BsonDocumentPipelineStageDefinition(new BsonDocument("$out", outDocument));
}
@@ -1331,7 +1338,7 @@ public static PipelineStageDefinition Project(
///
///
/// Flag that specifies whether to return a detailed breakdown
- /// of the score for each document in the result.
+ /// of the score for each document in the result.
///
/// The stage.
public static PipelineStageDefinition Search(
diff --git a/tests/MongoDB.Driver.Core.Tests/Core/Operations/AggregateToCollectionOperationTests.cs b/tests/MongoDB.Driver.Core.Tests/Core/Operations/AggregateToCollectionOperationTests.cs
index 65b4a9ab110..b45edc47149 100644
--- a/tests/MongoDB.Driver.Core.Tests/Core/Operations/AggregateToCollectionOperationTests.cs
+++ b/tests/MongoDB.Driver.Core.Tests/Core/Operations/AggregateToCollectionOperationTests.cs
@@ -607,6 +607,43 @@ public void Execute_should_return_expected_result(
result.Should().HaveCount(1);
}
+ [Theory]
+ [ParameterAttributeData]
+ public void Execute_to_time_series_collection_should_work(
+ [Values(false, true)] bool usingDifferentOutputDatabase,
+ [Values(false, true)] bool async)
+ {
+ RequireServer.Check().Supports(Feature.AggregateOutTimeSeries);
+
+ var pipeline = new List { BsonDocument.Parse("{ $match : { _id : 1 } }") };
+ var inputDatabaseName = _databaseNamespace.DatabaseName;
+ var inputCollectionName = _collectionNamespace.CollectionName;
+ var outputDatabaseName = usingDifferentOutputDatabase ? $"{inputDatabaseName}-outputdatabase-timeseries" : inputDatabaseName;
+ var outputCollectionName = $"{inputCollectionName}-outputcollection-timeseries";
+
+ pipeline.Add(new BsonDocument { {"$set", new BsonDocument { {"time", DateTime.Now } } } } );
+ pipeline.Add(BsonDocument.Parse($"{{ $out : {{ db : '{outputDatabaseName}', coll : '{outputCollectionName}', timeseries: {{ timeField: 'time' }} }} }}"));
+
+ EnsureTestData();
+ if (usingDifferentOutputDatabase)
+ {
+ EnsureDatabaseExists(outputDatabaseName);
+ }
+ var subject = new AggregateToCollectionOperation(_collectionNamespace, pipeline, _messageEncoderSettings);
+
+ ExecuteOperation(subject, async);
+
+ var databaseNamespace = new DatabaseNamespace(outputDatabaseName);
+ var result = ReadAllFromCollection(new CollectionNamespace(databaseNamespace, outputCollectionName), async);
+
+ result.Should().NotBeNull();
+ result.Should().HaveCount(1);
+
+ var output = ListCollections(databaseNamespace);
+ output["cursor"]["firstBatch"][0][0].ToString().Should().Be($"{outputCollectionName}"); // checking name of collection
+ output["cursor"]["firstBatch"][0][1].ToString().Should().Be("timeseries"); // checking type of collection
+ }
+
[Theory]
[ParameterAttributeData]
public void Execute_should_return_expected_result_when_AllowDiskUse_is_set(
diff --git a/tests/MongoDB.Driver.Core.Tests/Core/Operations/OperationTestBase.cs b/tests/MongoDB.Driver.Core.Tests/Core/Operations/OperationTestBase.cs
index 1d2ee9bdac7..6e2335dd166 100644
--- a/tests/MongoDB.Driver.Core.Tests/Core/Operations/OperationTestBase.cs
+++ b/tests/MongoDB.Driver.Core.Tests/Core/Operations/OperationTestBase.cs
@@ -347,6 +347,19 @@ protected void KillOpenTransactions()
}
}
+ protected BsonDocument ListCollections(DatabaseNamespace databaseNamespace)
+ {
+ var listCollectionsCommand = new BsonDocument
+ {
+ { "listCollections", 1 }, { "filter", new BsonDocument { { "type", "timeseries" } } }
+ };
+
+ var runCommandOperation = new ReadCommandOperation(databaseNamespace, listCollectionsCommand,
+ BsonDocumentSerializer.Instance, _messageEncoderSettings);
+
+ return ExecuteOperation(runCommandOperation);
+ }
+
protected Profiler Profile(DatabaseNamespace databaseNamespace)
{
var op = new WriteCommandOperation(
diff --git a/tests/MongoDB.Driver.Tests/AggregateFluentTests.cs b/tests/MongoDB.Driver.Tests/AggregateFluentTests.cs
index 5f538d76e00..934ac347533 100644
--- a/tests/MongoDB.Driver.Tests/AggregateFluentTests.cs
+++ b/tests/MongoDB.Driver.Tests/AggregateFluentTests.cs
@@ -710,7 +710,8 @@ public void OfType_should_add_the_expected_stage(
[Theory]
[ParameterAttributeData]
public void Out_with_collection_should_add_the_expected_stage_and_call_Aggregate(
- [Values(false, true)] bool async)
+ [Values(false, true)] bool async,
+ [Values(true, false)] bool usingTimeSeriesCollection)
{
var inputDatabase = CreateMockDatabase("inputDatabaseName").Object;
var mockInputCollection = CreateMockCollection(inputDatabase, "inputCollectionName");
@@ -720,20 +721,27 @@ public void Out_with_collection_should_add_the_expected_stage_and_call_Aggregate
var outputDatabase = CreateMockDatabase("outputDatabaseName").Object;
var outputCollection = outputDatabase.GetCollection("outputCollectionName");
+ var timeSeriesOption = usingTimeSeriesCollection ? new TimeSeriesOptions("time") : null;
+ var expectedRenderedOutStage = usingTimeSeriesCollection
+ ? "{ $out : { db : 'outputDatabaseName', coll : 'outputCollectionName', timeseries: { timeField: 'time' } } }"
+ : "{ $out : { db : 'outputDatabaseName', coll : 'outputCollectionName' } }";
+
Predicate> isExpectedPipeline = pipeline =>
{
var renderedPipeline = RenderPipeline(pipeline);
return
renderedPipeline.Documents.Count == 2 &&
renderedPipeline.Documents[0] == BsonDocument.Parse("{ $match : { X : 1 } }") &&
- renderedPipeline.Documents[1] == BsonDocument.Parse("{ $out : { db : 'outputDatabaseName', coll : 'outputCollectionName' } }") &&
+ renderedPipeline.Documents[1] == BsonDocument.Parse(expectedRenderedOutStage) &&
renderedPipeline.OutputSerializer.ValueType == typeof(C);
};
IAsyncCursor cursor;
if (async)
{
- cursor = subject.OutAsync(outputCollection, CancellationToken.None).GetAwaiter().GetResult();
+ cursor = usingTimeSeriesCollection
+ ? subject.OutAsync(outputCollection, timeSeriesOption, CancellationToken.None).GetAwaiter().GetResult()
+ : subject.OutAsync(outputCollection, CancellationToken.None).GetAwaiter().GetResult();
mockInputCollection.Verify(
c => c.AggregateAsync(
@@ -744,7 +752,9 @@ public void Out_with_collection_should_add_the_expected_stage_and_call_Aggregate
}
else
{
- cursor = subject.Out(outputCollection, CancellationToken.None);
+ cursor = usingTimeSeriesCollection
+ ? subject.Out(outputCollection, timeSeriesOption, CancellationToken.None)
+ : subject.Out(outputCollection, CancellationToken.None);
mockInputCollection.Verify(
c => c.Aggregate(
@@ -758,7 +768,8 @@ public void Out_with_collection_should_add_the_expected_stage_and_call_Aggregate
[Theory]
[ParameterAttributeData]
public void Out_with_string_should_add_the_expected_stage_and_call_Aggregate(
- [Values(false, true)] bool async)
+ [Values(false, true)] bool async,
+ [Values(true, false)] bool usingTimeSeriesCollection)
{
var inputDatabase = CreateMockDatabase("inputDatabaseName").Object;
var mockInputCollection = CreateMockCollection(inputDatabase, "inputCollectionName");
@@ -767,20 +778,27 @@ public void Out_with_string_should_add_the_expected_stage_and_call_Aggregate(
.Match(Builders.Filter.Eq(c => c.X, 1));
var outputCollectionName = "outputCollectionName";
+ var timeSeriesOption = usingTimeSeriesCollection ? new TimeSeriesOptions("time") : null;
+ var expectedRenderedOutStage = usingTimeSeriesCollection
+ ? "{ $out : { db : 'inputDatabaseName', coll : 'outputCollectionName', timeseries: { timeField: 'time' } } }"
+ : "{ $out : { db : 'inputDatabaseName', coll : 'outputCollectionName' } }";
+
Predicate> isExpectedPipeline = pipeline =>
{
var renderedPipeline = RenderPipeline(pipeline);
return
renderedPipeline.Documents.Count == 2 &&
renderedPipeline.Documents[0] == BsonDocument.Parse("{ $match : { X : 1 } }") &&
- renderedPipeline.Documents[1] == BsonDocument.Parse("{ $out : { db : 'inputDatabaseName', coll : 'outputCollectionName' } }") &&
+ renderedPipeline.Documents[1] == BsonDocument.Parse(expectedRenderedOutStage) &&
renderedPipeline.OutputSerializer.ValueType == typeof(C);
};
IAsyncCursor cursor;
if (async)
{
- cursor = subject.OutAsync(outputCollectionName, CancellationToken.None).GetAwaiter().GetResult();
+ cursor = usingTimeSeriesCollection
+ ? subject.OutAsync(outputCollectionName, timeSeriesOption, CancellationToken.None).GetAwaiter().GetResult()
+ : subject.OutAsync(outputCollectionName, CancellationToken.None).GetAwaiter().GetResult();
mockInputCollection.Verify(
c => c.AggregateAsync(
@@ -791,7 +809,9 @@ public void Out_with_string_should_add_the_expected_stage_and_call_Aggregate(
}
else
{
- cursor = subject.Out(outputCollectionName, CancellationToken.None);
+ cursor = usingTimeSeriesCollection
+ ? subject.Out(outputCollectionName, timeSeriesOption, CancellationToken.None)
+ : subject.Out(outputCollectionName, CancellationToken.None);
mockInputCollection.Verify(
c => c.Aggregate(
diff --git a/tests/MongoDB.Driver.Tests/Jira/CSharp3397Tests.cs b/tests/MongoDB.Driver.Tests/Jira/CSharp3397Tests.cs
index 97d3ed80f5b..9de4ddb7eef 100644
--- a/tests/MongoDB.Driver.Tests/Jira/CSharp3397Tests.cs
+++ b/tests/MongoDB.Driver.Tests/Jira/CSharp3397Tests.cs
@@ -13,10 +13,13 @@
* limitations under the License.
*/
+using System;
using System.Linq;
using FluentAssertions;
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;
+using MongoDB.Driver.Core.Misc;
+using MongoDB.Driver.Core.TestHelpers.XunitExtensions;
using Xunit;
namespace MongoDB.Driver.Tests.Jira
@@ -52,6 +55,47 @@ public void Aggregate_out_to_collection_should_work()
results.Single().Count.Should().Be(1);
}
+
+ [Fact]
+ public void Aggregate_out_to_time_series_collection_on_secondary_should_work()
+ {
+ RequireServer.Check().Supports(Feature.AggregateOutTimeSeries);
+
+ var client = DriverTestConfiguration.Client;
+ var database = client.GetDatabase("test");
+ var collection = database.GetCollection("testCol");
+ var outCollection = database.GetCollection("timeCol");
+
+ var writeConcern = WriteConcern.WMajority;
+ if (DriverTestConfiguration.IsReplicaSet(client))
+ {
+ var n = DriverTestConfiguration.GetReplicaSetNumberOfDataBearingMembers(client);
+ writeConcern = new WriteConcern(n);
+ }
+
+ database.DropCollection("testCol");
+ database.DropCollection("timeCol");
+ collection
+ .WithWriteConcern(writeConcern)
+ .InsertOne(new BsonDocument("_id", 1));
+
+ var fields = Builders.SetFields.Set("time", DateTime.Now);
+ var pipeline = new EmptyPipelineDefinition()
+ .Match(FilterDefinition.Empty)
+ .Set(fields)
+ .Out(outCollection, new TimeSeriesOptions("time"));
+
+ var results = collection.WithReadPreference(ReadPreference.SecondaryPreferred).Aggregate(pipeline).ToList();
+ results.Count.Should().Be(1);
+
+ var listCollectionsCommand = new BsonDocument
+ {
+ { "listCollections", 1 }, { "filter", new BsonDocument { { "type", "timeseries" } } }
+ };
+ var output = database.RunCommand(listCollectionsCommand);
+ output["cursor"]["firstBatch"][0][0].ToString().Should().Be("timeCol"); // checking name of collection
+ output["cursor"]["firstBatch"][0][1].ToString().Should().Be("timeseries"); // checking type of collection
+ }
}
public class AggregateCountResultWithId
diff --git a/tests/MongoDB.Driver.Tests/PipelineDefinitionBuilderTests.cs b/tests/MongoDB.Driver.Tests/PipelineDefinitionBuilderTests.cs
index 60865833867..1e9250f8a61 100644
--- a/tests/MongoDB.Driver.Tests/PipelineDefinitionBuilderTests.cs
+++ b/tests/MongoDB.Driver.Tests/PipelineDefinitionBuilderTests.cs
@@ -141,6 +141,23 @@ public void Merge_should_add_expected_stage()
stages[0].Should().Be("{ $merge : { into : { db : 'database', coll : 'collection' } } }");
}
+ [Fact]
+ public void Out_with_time_series_options_should_add_expected_stage()
+ {
+ var database = Mock.Of(db => db.DatabaseNamespace == new DatabaseNamespace("database"));
+ var outputCollection = Mock.Of>(col =>
+ col.Database == database &&
+ col.CollectionNamespace == new CollectionNamespace(database.DatabaseNamespace, "collection"));
+
+ var timeSeriesOptions = new TimeSeriesOptions("time", "symbol");
+
+ var result = new EmptyPipelineDefinition().Out(outputCollection, timeSeriesOptions);
+
+ var stages = RenderStages(result, BsonDocumentSerializer.Instance);
+ stages.Count.Should().Be(1);
+ stages[0].Should().Be("{ $out: { db: 'database', coll: 'collection', timeseries: { timeField: 'time', metaField: 'symbol' } } }");
+ }
+
[Fact]
public void Search_should_add_expected_stage()
{
diff --git a/tests/MongoDB.Driver.Tests/PipelineStageDefinitionBuilderTests.cs b/tests/MongoDB.Driver.Tests/PipelineStageDefinitionBuilderTests.cs
index 397636e8950..0c23a903e71 100644
--- a/tests/MongoDB.Driver.Tests/PipelineStageDefinitionBuilderTests.cs
+++ b/tests/MongoDB.Driver.Tests/PipelineStageDefinitionBuilderTests.cs
@@ -20,7 +20,9 @@
using MongoDB.Bson.Serialization;
using MongoDB.Bson.Serialization.Attributes;
using MongoDB.Bson.Serialization.Serializers;
+using MongoDB.Driver.Core.TestHelpers;
using MongoDB.Driver.Core.TestHelpers.XunitExtensions;
+using Moq;
using Xunit;
namespace MongoDB.Driver.Tests
@@ -183,7 +185,7 @@ public void GraphLookup_with_one_to_many_parameters_should_return_expected_resul
}
}");
}
-
+
[Fact]
public void GraphLookup_with_one_to_one_parameters_should_return_expected_result()
{
@@ -254,9 +256,9 @@ public void Lookup_with_let_should_return_the_expected_result()
'pipeline' : [
{
'$match' :
- {
+ {
'$expr' :
- {
+ {
'$and' : [
{ '$eq' : ['$stock_item', '$$order_item'] },
{ '$gte' : ['$instock', '$$order_qty'] }]
@@ -391,6 +393,21 @@ public void Merge_with_WhenNotMatched_should_return_the_expected_result(MergeSta
stage.Document.Should().Be(expectedStage);
}
+ [Fact]
+ public void Out_with_time_series_options_should_return_expected_result()
+ {
+ var database = Mock.Of(d => d.DatabaseNamespace == new DatabaseNamespace("database"));
+ var outputCollection = Mock.Of>(col =>
+ col.Database == database &&
+ col.CollectionNamespace == new CollectionNamespace(database.DatabaseNamespace, "collection"));
+
+ var timeSeriesOptions = new TimeSeriesOptions("time", "symbol");
+
+ var result = PipelineStageDefinitionBuilder.Out(outputCollection, timeSeriesOptions);
+
+ RenderStage(result).Document.Should().Be("{ $out: { db: 'database', coll: 'collection', timeseries: { timeField: 'time', metaField: 'symbol' } } }");
+ }
+
public class Order
{
[BsonElement("stockdata")]
@@ -456,7 +473,7 @@ public void Lookup_with_entity_generic_params_should_return_the_expected_result(
'$match' :
{
'$expr' :
- {
+ {
'$and' : [
{ '$eq' : ['$stock_item', '$$order_item'] },
{ '$gte' : ['$instock', '$$order_qty'] }]