Mongo Aggregate with distinct from Collection using C# Driver - c#

I have the following working aggregate statement in MongoDB:
db.Forms.aggregate( [
{ $match: { Id: { $nin: db.Forms.distinct("Id", {"Status": "DELETE"}, {Id: 1}) } }},
{ $group: { _id: "$Id", lastModifiedId: { $last: "$_id" } } }
]).result
The statement selects all Forms that do not have a delete record on the Forms table and returns their last modified rows.
What I would like to know is: how do I write the aggregate statement above using the MongoDB C# driver? This is what I have so far:
var aggregate = _forms.Aggregate()
//.Match(new BsonDocument { { "Id", new BsonDocument("$nin", "db.Forms.distinct(\"Id\", {\"Status\": \"DELETE\"}, {Id: 1})") } })
.Group(new BsonDocument { { "_id", "$Id" }, { "lastModifiedId", new BsonDocument("$last", "_id") } });
var aggregateResults = aggregate.ToListAsync().Result.ToList();
I just need to get the Match statement sorted out.
I've looked at a few articles about aggregation and I understand the concept (I think), but the "db.Forms.distinct" is where I'm having issues and none of the articles that I found handled this scenario.
If there's a better way of doing this, please let me know.
Thank you!

Related

Querying a collection via a match in an ID-to-ID collection in MongoDB using C# Driver

I have the following collection document types:
Car
{
Id
Make
Model
}
and
UserCar
{
UserId
CarId (references Car.Id)
}
I'm having trouble finding the correct query using MongoDB C# Driver to:
Get all Cars where UserId = x
This is a very simple query in SQL, so I'm quite frustrated that this is proving so difficult with their SDK (for me, at least). It's the ID-to-ID collection containing the filter that seems to be the issue. So, starting with:
var db = MongoUtil.GetDb();
var cars = db.GetCollection<Car>("Cars");
var userCars = db.GetCollection<UserCar>("UserCars");
List<Car> carsJoined = ??? where UserId = 1234
Thanks for the help.
Work with MongoDB .NET Driver .Aggregate() (Although the query below looks a bit complex).
var result = cars
.Aggregate()
.Lookup<UserCar, BsonDocument>(
"UserCars",
"Id",
"CarId",
"userCars")
.Match(Builders<BsonDocument>.Filter
.ElemMatch<BsonValue>("userCars", new BsonDocument("UserId", 1234)))
.Project<masterDocument>(Builders<BsonDocument>.Projection
.Exclude("userCars"))
.ToList();
This is equivalent to the aggregate query
db.cars.aggregate([
{
$lookup: {
from: "UserCars",
localField: "Id"
foreignField: "CarId",
as: "userCars"
}
},
{
$match: {
"userCars": {
$elemMatch: {
"UserId": 1234
}
}
}
},
{
$project: {
userCars: 0,
// Other fields: 1
}
}
])

Translating MongoDb query to MongoDriver .Net core

I'm trying to translate the following MongoDb command to its equivalent in MongoDriver for .Net Core:
db.test.aggregate([
{
$project: {
values: {
$map: {
input: { $objectToArray: "$foo" },
as: "val",
in: "$$val.v.value"
}
}
}
}
]);
But I'm having a bad time trying to understand the docs since I see a lot of references to types that my compiler cannot find (like AggregateArgs). What would be the best way of expressing it using C# syntax?
Try this:
var projectStage = BsonDocument.Parse(#"
{
'values' : {
'$map' : {
'input' : {
'$objectToArray' : '$foo'
},
'as': 'val',
'in': '$$val.v.value'
}
}}");
var coll = new MongoClient().GetDatabase("db").GetCollection<BsonDocument>("coll");
var res = coll
.Aggregate()
.Project(projectStage)
.ToList();
The generated projection query will be:
{
"$project": {
"values": {
"$map": {
"input": {
"$objectToArray": "$foo"
},
"as": "val",
"in": "$$val.v.value"
}
}
}
}
Unfortunately, $objectToArray currently is not supported via the typed way. You can find how similar queries with typed way and LINQ can look like here: https://github.com/mongodb/mongo-csharp-driver/blob/master/tests/MongoDB.Driver.Tests/Linq/Translators/AggregateProjectTranslatorTests.cs

Get a nested fields total count from a mongo collection with C#, MongoDb.Driver

I have a mongo collection, shown below :
I am using C#, ASP .Net Core 2.0 MongoDB 3.6
I need to get the count of those TopicVideo Object, which have videolinks value(at least not empty)
Count(distinct VideoLink) From TopicVideo Where videolink is not null
of it will be enough for me to check if it starts with http or not.
Here is a code, I have tried but not working.
var teahcersCollection = database.GetCollection<BsonDocument>("Teachers");
return teahcersCollection.Count(Builders<BsonDocument>.Filter.Regex("TopicVideo.VideoLink'", "/http.*/"));
Again, To clear, how to get the count of videoLink in this scenario?
The Other thing
And another thing, I am struggling too much with this type of queries and I want to query from the collection. please refer me any good step by step detailed documentation if you think available.
You can use the following aggregation query:
var teachersCollection = database.GetCollection<Teacher>("Teachers");
var regexFilter = Builders<BsonDocument>.Filter.Regex("TopicVideo.VideoLink", "/^http/");
var httpBsonCount = teachersCollection.Aggregate()
.Unwind(t => t.TopicVideo)
.Match(regexFilter)
.Group(new BsonDocument { { "_id", "null" }, { "count", new BsonDocument { { "$sum", 1 } } } })
.ToList();
int httpCount = 0;
if (httpBsonCount.Any())
httpCount = httpBsonCount.First()["count"].AsInt32;
Once executed the query, httpCount will contain your expected value.
In the mongo console, the query looks like:
db.Teachers.aggregate([
{ $unwind: "$TopicVideo"},
{ $match: { "TopicVideo.VideoLink": /^http/ } },
{ $group: { _id: null, count: { $sum : 1 } } }
]);
In order to learn about how to query MongoDB through C# driver I suggest you to follow the free M101N course.

Executing Aggregate framework query in c#

I am trying to create a console application which will read through a Mongo db and filter out some data based on some business logic and display the results on console screen.
Till now I am able to write the following query and execute it successfully on Mongo shell. Here is the query:
{db.Collection.aggregate([
{$unwind: { path: "$Pages"}},
{$group : {
_id :{UrlPath: "$Pages.Url.Path", I_Id : "$_id", Date: { $dateToString: { format: "%Y-%m-%d",date: "$Pages.DateTime"}}, CId: "$CId",
x: {$sum:1},
y : {$sum:"$V"}
}},
{$group : {
_id : {Date: "$_id.Date",CId: "$_id.CId", PageUrl: "$_id.UrlPath"},
p: {$sum:1},
q : {$sum:"$x"},
TotalCount: {$sum:"$y"}
}},
{$sort:{p:-1}},
],{allowDiskUse: true}).pretty();
};
The problem I am facing is replicating the same query logic in C# code. Till now I able to connect to mongo db collections and able to basic CRUD operations.
But replicating this aggregate logic is really blowing my mind. I have tried using PipelineDefinition option but can't manage to get correct output out of it.
Can some one please guide me in the correct direction here.
Thanks in advance
Finally I was able to achieve it using collection.Aggregate() method.
Code looks like this:
collection.Aggregate(new AggregateOptions { AllowDiskUse = true})
.Unwind(i => i.Pages)
.Group(new BsonDocument
{
{
"_id", new BsonDocument
{
{ "Date", new BsonDocument("$dateToString", new BsonDocument {{"format", "%Y-%m-%d"}, {"date", "$Pages.DateTime"}})},
{"CId","$_id"}
}
},
{
"x", new BsonDocument
{
{"$sum", "$Value"}
}
}
}
)
.Group(new BsonDocument
{
{
"_id", new BsonDocument
{
{"Date", "$_id.Date"},
{"CId", "$_id.CId"}
}
},
{
"p", new BsonDocument
{
{"$sum", 1}
}
},
{
"q", new BsonDocument
{
{"$sum", "$x"}
}
}
}
)
.Sort(new BsonDocument("q", -1))
.ToList();

C# MongoDB driver 2.0 - Getting distance back from near query

I am doing a NearSphere query with the C# MongoDB driver 2.0 and it works fine.
The results are ordered by distance automatically but I would like to get that distance back for each of the search results to be able to display it back.
I found this post that says how to do it for the old version of the driver Retrieving the Distance "dis" result from a Near query but didn't manage to find how to do it with the new drivers.
This is my code:
var collection = database.GetCollection<MyType>("myTypes");
var locFilter = Builders<MyType>.Filter.NearSphere(x => x.GeoLocation, criteria.Long, criteria.Lat, criteria.RadiusInMiles/3963.2);
var results = await collection.Find(locFilter).ToListAsync();
I guess I have to do something before calling ToList on the IFindFluent result ?
Any help ?
Thanks a lot
The C# MongoDB Driver lacks of some operations but the reality there's not any restriction querying the database. The methods Project, Match and so forth are just helpers to build a PipeLine that's exactly a BsonDocument like any other.
I had to query the database from C# using a similar approach to yours:
db.mycoll.aggregate(
[ { $geoNear :
{ near : { type : "Point", coordinates : [-34.5460069,-58.48894900000001] },
distanceField : "dist.calculated", maxDistance : 100,
includeLocs : "dist.location",
num : 5, spherical : true }
} ,
{ $project : {_id: 1, place_id:1, name:1, dist:1} }
] ).pretty()
As you know there's not a geoNear method to build it in the driver, so you can just create the BsonDocument.
To show you that everything can be built in that way find below a sample query from C# not using the project clausule either, I built it from the BsonDocument. You can push BsonDocument's in the pipeline as you wish.
var coll = _database.GetCollection<UrbanEntity>("mycoll");
var geoNearOptions = new BsonDocument {
{ "near", new BsonDocument {
{ "type", "Point" },
{ "coordinates", new BsonArray {-34.5460069,-58.48894900000001} },
} },
{ "distanceField", "dist.calculated" },
{ "maxDistance", 100 },
{ "includeLocs", "dist.location" },
{ "num", 5 },
{ "spherical" , true }
};
var projectOptions = new BsonDocument {
{ "_id" , 1 },
{ "place_id", 1 },
{ "name" , 1 },
{ "dist", 1}
};
var pipeline = new List<BsonDocument>();
pipeline.Add( new BsonDocument { {"$geoNear", geoNearOptions} });
pipeline.Add( new BsonDocument { {"$project", projectOptions} });
using(var cursor = await coll.AggregateAsync<BsonDocument>(pipeline)) {
while(await cursor.MoveNextAsync()) {
foreach (var doc in cursor.Current) {
// Here you have the documents ready to read
}
}
}
I hope it helps.

Categories

Resources