public void Use_a_time_range_window_with_a_positive_upper_bound_example_should_work() { RequireServer.Check().Supports(Feature.SetWindowFields); var collection = Setup(); var aggregate = collection .Aggregate() .SetWindowFields( partitionBy: x => x.State, sortBy: Builders <CakeSales> .Sort.Ascending(x => x.OrderDate), output: p => new { RecentOrders = p.Push(x => x.OrderDate, RangeWindow.Create(RangeWindow.Unbounded, RangeWindow.Months(10))) }); var stages = Linq3TestHelpers.Translate(collection, aggregate); var expectedStages = new[] { @" { $setWindowFields : { partitionBy : '$State', sortBy : { OrderDate : 1 }, output : { RecentOrders : { $push : '$OrderDate', window : { range : ['unbounded', 10], unit : 'month' } } } } } " }; Linq3TestHelpers.AssertStages(stages, expectedStages); var results = aggregate.ToList(); results.Count.Should().Be(6); results[0].Should().Be("{ _id : 4, Type : 'strawberry', OrderDate : ISODate('2019-05-18T16:09:01Z'), State : 'CA', Price : 41.00, Quantity : 162, RecentOrders : [ISODate('2019-05-18T16:09:01Z')] }"); results[1].Should().Be("{ _id : 0, Type : 'chocolate', OrderDate : ISODate('2020-05-18T14:10:30Z'), State : 'CA', Price : 13.00, Quantity : 120, RecentOrders : [ISODate('2019-05-18T16:09:01Z'), ISODate('2020-05-18T14:10:30Z'), ISODate('2021-01-11T06:31:15Z')] }"); results[2].Should().Be("{ _id : 2, Type : 'vanilla', OrderDate : ISODate('2021-01-11T06:31:15Z'), State : 'CA', Price : 12.00, Quantity : 145, RecentOrders : [ISODate('2019-05-18T16:09:01Z'), ISODate('2020-05-18T14:10:30Z'), ISODate('2021-01-11T06:31:15Z')] }"); results[3].Should().Be("{ _id : 5, Type : 'strawberry', OrderDate : ISODate('2019-01-08T06:12:03Z'), State : 'WA', Price : 43.00, Quantity : 134, RecentOrders : [ISODate('2019-01-08T06:12:03Z')] }"); results[4].Should().Be("{ _id : 3, Type : 'vanilla', OrderDate : ISODate('2020-02-08T13:13:23Z'), State : 'WA', Price : 13.00, Quantity : 104, RecentOrders : [ISODate('2019-01-08T06:12:03Z'), ISODate('2020-02-08T13:13:23Z')] }"); results[5].Should().Be("{ _id : 1, Type : 'chocolate', OrderDate : ISODate('2021-03-20T11:30:05Z'), State : 'WA', Price : 14.00, Quantity : 140, RecentOrders : [ISODate('2019-01-08T06:12:03Z'), ISODate('2020-02-08T13:13:23Z'), ISODate('2021-03-20T11:30:05Z')] }"); }
public void Where_with_dynamically_created_predicate_should_work( [Values("x", null)] string parameterName) { var collection = GetCollection(); var predicate = MakePredicate(parameterName); var queryable = collection.AsQueryable() .Where(predicate); var stages = Linq3TestHelpers.Translate(collection, queryable); var expectedStages = new[] { "{ $match : { X : { $gt : 0 } } }" }; Linq3TestHelpers.AssertStages(stages, expectedStages); }
public void ToLower_with_Equals_should_work_in_Select() { var client = DriverTestConfiguration.Linq3Client; var database = client.GetDatabase("test"); var collection = database.GetCollection <C>("test"); var queryable = collection.AsQueryable() .Select(x => new { Result = x.S.ToLower().Equals("abc") }); var stages = Linq3TestHelpers.Translate(collection, queryable); var expectedStages = new[] { "{ $project : { Result : { $eq : [{ $toLower : '$S' }, 'abc'] }, _id : 0 } }" }; Linq3TestHelpers.AssertStages(stages, expectedStages); }
public void ToLower_with_Equals_should_work_in_Where() { var client = DriverTestConfiguration.Linq3Client; var database = client.GetDatabase("test"); var collection = database.GetCollection <C>("test"); var queryable = collection.AsQueryable() .Where(x => x.S.ToLower().Equals("abc")); var stages = Linq3TestHelpers.Translate(collection, queryable); var expectedStages = new[] { "{ $match : { S : /^abc$/is } }" }; Linq3TestHelpers.AssertStages(stages, expectedStages); }
public void Use_documents_window_to_obtain_cumulative_quantity_for_each_year_example_should_work() { RequireServer.Check().Supports(Feature.SetWindowFields); var collection = Setup(); var aggregate = collection .Aggregate() .SetWindowFields( partitionBy: x => x.OrderDate.Year, sortBy: Builders <CakeSales> .Sort.Ascending(x => x.OrderDate), output: p => new { CumulativeQuantityForYear = p.Sum(x => x.Quantity, DocumentsWindow.Create(DocumentsWindow.Unbounded, DocumentsWindow.Current)) }); var stages = Linq3TestHelpers.Translate(collection, aggregate); var expectedStages = new[] { @" { $setWindowFields : { partitionBy : { $year : '$OrderDate' } , sortBy : { OrderDate : 1 }, output : { CumulativeQuantityForYear : { $sum : '$Quantity', window : { documents : ['unbounded', 'current'] } } } } } " }; Linq3TestHelpers.AssertStages(stages, expectedStages); var results = aggregate.ToList(); results.Count.Should().Be(6); results[0].Should().Be("{ _id : 5, Type : 'strawberry', OrderDate : ISODate('2019-01-08T06:12:03Z'), State : 'WA', Price : 43.00, Quantity : 134, CumulativeQuantityForYear : 134 }"); results[1].Should().Be("{ _id : 4, Type : 'strawberry', OrderDate : ISODate('2019-05-18T16:09:01Z'), State : 'CA', Price : 41.00, Quantity : 162, CumulativeQuantityForYear : 296 }"); results[2].Should().Be("{ _id : 3, Type : 'vanilla', OrderDate : ISODate('2020-02-08T13:13:23Z'), State : 'WA', Price : 13.00, Quantity : 104, CumulativeQuantityForYear : 104 }"); results[3].Should().Be("{ _id : 0, Type : 'chocolate', OrderDate : ISODate('2020-05-18T14:10:30Z'), State : 'CA', Price : 13.00, Quantity : 120, CumulativeQuantityForYear : 224 }"); results[4].Should().Be("{ _id : 2, Type : 'vanilla', OrderDate : ISODate('2021-01-11T06:31:15Z'), State : 'CA', Price : 12.00, Quantity : 145, CumulativeQuantityForYear : 145 }"); results[5].Should().Be("{ _id : 1, Type : 'chocolate', OrderDate : ISODate('2021-03-20T11:30:05Z'), State : 'WA', Price : 14.00, Quantity : 140, CumulativeQuantityForYear : 285 }"); }
public void Range_window_example_should_work() { RequireServer.Check().Supports(Feature.SetWindowFields); var collection = Setup(); var aggregate = collection .Aggregate() .SetWindowFields( partitionBy: x => x.State, sortBy: Builders <CakeSales> .Sort.Ascending(x => x.Price), output: p => new { QuantityFromSimilarOrders = p.Sum(x => x.Quantity, RangeWindow.Create(-10, 10)) }); var stages = Linq3TestHelpers.Translate(collection, aggregate); var expectedStages = new[] { @" { $setWindowFields : { partitionBy : '$State', sortBy : { Price : 1 }, output : { QuantityFromSimilarOrders : { $sum : '$Quantity', window : { range : [-10.0, 10.0] } } } } } " }; Linq3TestHelpers.AssertStages(stages, expectedStages); var results = aggregate.ToList(); results.Count.Should().Be(6); results[0].Should().Be("{ _id : 2, Type : 'vanilla', OrderDate : ISODate('2021-01-11T06:31:15Z'), State : 'CA', Price : 12.00, Quantity : 145, QuantityFromSimilarOrders : 265 }"); results[1].Should().Be("{ _id : 0, Type : 'chocolate', OrderDate : ISODate('2020-05-18T14:10:30Z'), State : 'CA', Price : 13.00, Quantity : 120, QuantityFromSimilarOrders : 265 }"); results[2].Should().Be("{ _id : 4, Type : 'strawberry', OrderDate : ISODate('2019-05-18T16:09:01Z'), State : 'CA', Price : 41.00, Quantity : 162, QuantityFromSimilarOrders : 162 }"); results[3].Should().Be("{ _id : 3, Type : 'vanilla', OrderDate : ISODate('2020-02-08T13:13:23Z'), State : 'WA', Price : 13.00, Quantity : 104, QuantityFromSimilarOrders : 244 }"); results[4].Should().Be("{ _id : 1, Type : 'chocolate', OrderDate : ISODate('2021-03-20T11:30:05Z'), State : 'WA', Price : 14.00, Quantity : 140, QuantityFromSimilarOrders : 244 }"); results[5].Should().Be("{ _id : 5, Type : 'strawberry', OrderDate : ISODate('2019-01-08T06:12:03Z'), State : 'WA', Price : 43.00, Quantity : 134, QuantityFromSimilarOrders : 134 }"); }
public void Filter_using_ToLower_with_equality_operator_should_work() { var collection = GetCollection(); var friendlyName = "Widget"; var queryable = from product in collection.AsQueryable() where product.FriendlyName.ToLower() == friendlyName.ToLower() select product; var stages = Linq3TestHelpers.Translate(collection, queryable); var expectedStages = new[] { "{ $match : { FriendlyName : /^widget$/is } }" }; Linq3TestHelpers.AssertStages(stages, expectedStages); }
public void ToUpperInvariant_with_Equals_should_work() { var collection = GetCollection(); var friendlyName = "Widget"; var queryable = from product in collection.AsQueryable() where product.FriendlyName.ToUpperInvariant().Equals(friendlyName.ToUpper()) select product; var stages = Linq3TestHelpers.Translate(collection, queryable); var expectedStages = new[] { "{ $match : { FriendlyName : /^WIDGET$/is } }" }; Linq3TestHelpers.AssertStages(stages, expectedStages); }
public void Group_with_First_should_work() { var client = DriverTestConfiguration.Linq3Client; var database = client.GetDatabase("test"); var collection = database.GetCollection <C>("test"); var aggregate = collection.Aggregate() .SortByDescending(x => x.CreatedDate) .Group(x => x.Key, g => g.First()); var stages = Linq3TestHelpers.Translate(collection, aggregate); var expectedStages = new[] { "{ $sort : { CreatedDate : -1 } }", "{ $group : { _id : '$Key', __agg0 : { $first : '$$ROOT' } } }", "{ $project : { _v : '$__agg0', _id : 0 } }" }; Linq3TestHelpers.AssertStages(stages, expectedStages); }
public void Nested_Select_should_work() { var client = DriverTestConfiguration.Linq3Client; var database = client.GetDatabase("FooBar"); var collection = database.GetCollection <FooNest>("Foos"); database.DropCollection("Foos"); collection.InsertOne( new FooNest { Name = "Parent", NestedCollection = new[] { new FooNest { Name = "Child" } } }); var queryable = collection.AsQueryable() .Select(top => top.NestedCollection.Select(child => new { ParentName = top.Name, child.Name })); var stages = Linq3TestHelpers.Translate(collection, queryable); var expectedStages = new[] { "{ $project : { _v : { $map : { input : '$NestedCollection', as : 'child', in : { ParentName : '$Name', Name : '$$child.Name' } } }, _id : 0 } }" }; Linq3TestHelpers.AssertStages(stages, expectedStages); var pipelineDefinition = new BsonDocumentStagePipelineDefinition <FooNest, BsonDocument>(stages); var resultAsDocument = collection.Aggregate(pipelineDefinition).ToList().Single(); resultAsDocument.Should().Be("{ _v : [{ ParentName : 'Parent', Name : 'Child' }] }"); var result = queryable.ToList().Single().ToList(); result.Should().HaveCount(1); result[0].ParentName.Should().Be("Parent"); result[0].Name.Should().Be("Child"); }
public void DefaultIfEmpty_with_explicit_default_should_work() { var client = DriverTestConfiguration.Linq3Client; var database = client.GetDatabase(DriverTestConfiguration.DatabaseNamespace.DatabaseName); var collection = database.GetCollection <C>(DriverTestConfiguration.CollectionNamespace.CollectionName); var subject = collection.AsQueryable(); database.DropCollection(collection.CollectionNamespace.CollectionName); collection.InsertMany(new[] { new C { Id = 1, InnerArray = new A[0] }, new C { Id = 2, InnerArray = new[] { new A { S = "abc" } } } }); var defaultValue = new A { S = "default" }; var queryable = subject.SelectMany(outerObject => outerObject.InnerArray.DefaultIfEmpty(defaultValue), (o, a) => new { o, a }); var stages = Linq3TestHelpers.Translate(collection, queryable); var expectedStages = new[] { "{ $project : { _v : { $map : { input : { $let : { vars : { source : '$InnerArray' }, in : { $cond : { if : { $eq : [{ $size : '$$source' }, 0] }, then : [{ S : 'default' }], else : '$$source' } } } }, as : 'a', in : { o : '$$ROOT', a : '$$a' } } }, _id : 0 } }", "{ $unwind : '$_v' }" }; Linq3TestHelpers.AssertStages(stages, expectedStages); var result = queryable.ToList(); result.Count.Should().Be(2); result[0].o.Id.Should().Be(1); result[0].a.S.Should().Be("default"); result[1].o.Id.Should().Be(2); result[1].a.S.Should().Be("abc"); }
public void Select_with_anonymous_type_followed_by_Where_and_Select_should_work() { var collection = CreateCollection(); var subject = collection.AsQueryable(); var tags = new[] { "tag1", "tag2" }; var queryable = subject .Select(c => new { doc = c, dif = c.X.Except(tags) }) .Where(c => c.dif.Count() == 0) .Select(c => c.doc); var stages = Linq3TestHelpers.Translate(collection, queryable); var expectedStages = new[] { "{ $project : { doc : '$$ROOT', dif : { $setDifference : ['$X', ['tag1', 'tag2']] }, _id : 0 } }", "{ $match : { dif : { $size : 0 } } }", "{ $project : { _v : '$doc', _id : 0 } }" // Select becomes $project, not $replaceRoot }; Linq3TestHelpers.AssertStages(stages, expectedStages); }
public void Nested_Select_should_work() { var client = DriverTestConfiguration.Linq3Client; var database = client.GetDatabase("foo"); var parents = database.GetCollection <Parent>("parents"); var children = database.GetCollection <Child>("children"); var grandChildren = database.GetCollection <GrandChild>("grandChildren"); database.DropCollection("parents"); database.DropCollection("children"); database.DropCollection("grandChildren"); parents.InsertMany(new[] { new Parent { Id = 1, Name = "parent1" }, new Parent { Id = 2, Name = "parent2" } }); children.InsertMany(new[] { new Child { Id = 1, Name = "child1", ParentId = 2 }, new Child { Id = 2, Name = "child2", ParentId = 1 } }); grandChildren.InsertMany(new[] { new GrandChild { Id = 1, Name = "grandchild1", ChildId = 2 }, new GrandChild { Id = 2, Name = "grandchild2", ChildId = 1 } }); var aggregate = parents .Aggregate() .Lookup <Parent, Child, ParentProjection>( children, parent => parent.Id, child => child.ParentId, parentProjection => parentProjection.Children) .Lookup <ParentProjection, GrandChild, GrandChild, IEnumerable <GrandChild>, ParentProjection>( grandChildren, let: new BsonDocument { { "children", "$Children" } }, lookupPipeline: new BsonDocumentStagePipelineDefinition <GrandChild, GrandChild>( new[] { BsonDocument.Parse(@"{ $match : { $expr : { $and : [ { $in : [ ""$ChildId"", ""$$children._id"" ] } ] } } }") }), childProjection => childProjection.GrandChildren) .Project(parent => new ParentTree { Id = parent.Id, ParentName = parent.Name, Children = parent.Children .Select(child => new ChildTree { Id = child.Id, Name = child.Name, GrandChildren = parent .GrandChildren .Where(gc => gc.ChildId == child.Id) .Select(gc => new GrandChildProjection() { Id = gc.Id, Name = gc.Name }) }) }); var stages = Linq3TestHelpers.Translate(parents, aggregate); var expectedStages = new[] { @"{ '$lookup':{ 'from':'children', 'localField':'_id', 'foreignField':'ParentId', 'as':'Children' } }", @"{ '$lookup':{ 'from':'grandChildren', 'let':{'children':'$Children'}, 'pipeline':[ { '$match':{'$expr':{'$and':[{'$in':['$ChildId','$$children._id']}]}}} ], 'as':'GrandChildren' } }", @"{ '$project':{ '_id':'$_id', 'ParentName':'$Name', 'Children':{ '$map':{ 'input':'$Children', 'as':'child', 'in':{ '_id':'$$child._id', 'Name':'$$child.Name', 'GrandChildren':{ '$map':{ 'input':{ '$filter':{ 'input':'$GrandChildren', 'as':'gc', 'cond':{ '$eq':[ '$$gc.ChildId', '$$child._id' ] } } }, 'as':'gc', 'in':{ '_id':'$$gc._id', 'Name':'$$gc.Name' } } } } } } } }" }; Linq3TestHelpers.AssertStages(stages, expectedStages); var pipelineDefinition = new BsonDocumentStagePipelineDefinition <Parent, BsonDocument>(expectedStages.Select(s => BsonDocument.Parse(s))); var resultBsonDocuments = parents.Aggregate(pipelineDefinition).ToList(); var expectedBsonDocuments = new[] { "{ '_id' : 1, 'ParentName' : 'parent1', 'Children' : [{ '_id' : 2, 'Name' : 'child2', 'GrandChildren' : [{ '_id' : 1, 'Name' : 'grandchild1' }] }] }", "{ '_id' : 2, 'ParentName' : 'parent2', 'Children' : [{ '_id' : 1, 'Name' : 'child1', 'GrandChildren' : [{ '_id' : 2, 'Name' : 'grandchild2' }] }] }" }; resultBsonDocuments.Should().Equal(expectedBsonDocuments.Select(d => BsonDocument.Parse(d))); var result = aggregate.ToList(); var expectedResults = new[] { new ParentTree { Id = 1, ParentName = "parent1", Children = new[] { new ChildTree { Id = 2, Name = "child2", GrandChildren = new[] { new GrandChildProjection { Id = 1, Name = "grandchild1" } } } } }, new ParentTree { Id = 2, ParentName = "parent2", Children = new[] { new ChildTree { Id = 1, Name = "child1", GrandChildren = new[] { new GrandChildProjection { Id = 2, Name = "grandchild2" } } } } } }; var parentTreeComparer = new ParentTreeComparer(); result.Should().Equal(expectedResults, (x, y) => parentTreeComparer.Equals(x, y)); }