C# using projection on MongoDB document - c#

I'm trying to get only a few values from an document that has been unwinded.
Right now I get all of this, but I only want the values from "reviews"
{ "_id" : ObjectId("57ced083857eda00e03b5a5e"), "name" : "Rest2", "reviews" : { "_id" : ObjectId("57ced083857eda00e03b5a60"), "rating" : 4, "date" : ISODate("2016-09-05T22:00:00Z") } }
My current aggregate function looks like this:
var coll = Database.GetCollection<Restaurant>("restaurants")
.Aggregate()
.Match(new BsonDocument { { "name", nameRest } })
.Unwind(x => x.reviews);
var result = await coll.ToListAsync();
How do you project only those values? Help would be greatly appreciated!

Based on your example, you can use project like below:
var coll = Database.GetCollection<Restaurant>("restaurants")
.Aggregate()
.Match(new BsonDocument { { "name", nameRest } })
.Unwind(x => x.reviews)
.Project(new BsonDocument { {"rating", "$reviews.rating"} })
var result = await coll.ToListAsync();
The result of the above example would output only reviews.rating and _id field. See aggregation operator $project for more information.
The snippet above was tested using MongoDB C# Driver v2.2, MongoDB v3.2 and .Net v4.5

Related

concat aggregate mongo db driver c#

I have some query written in c# using mongoDb driver.
var project = new BsonDocument
{
{ "Id" , "$asCompany._id"}, { "Code" , "$asCompany.Code"}, { "Name" , "$asCompany.Name"}, { "Address" , "$asCompany.Address"},
{ "ConcurrencyId" , new BsonDocument{ { "$concat", new BsonArray{ "1_3_", "$asCompany._id" } } } }
};
The above statement is using as project in the below code.
var joinresult3 = userCollection.Aggregate()
.Match(user => user.Id == userId)
.Lookup("Division", "Divisions.DivisionId", "_id", "asDivisons")
.Lookup("Company", "asDivisons.CompanyId", "_id", "asCompany")
.Project(project).ToList();
Ok, so the statement I wrote for projection is generating the following server side code. Which is seems to be correct.
{ "$project" : { "Id" : "$asCompany._id", "Code" : "$asCompany.Code", "Name" : "$asCompany.Name", "Address" : "$asCompany.Address", "ConcurrencyId" : { "$concat" : ["1_3_", "$asCompany._id"] } } }
But, the c# code is throwing following exception.
Command aggregate failed: $concat only supports strings, not array.
Thanks, in advance.

translating mongo query to C# by using Filter

Is there any way to use Filters in C# and translate this mongo query?
{'EmailData.Attachments.Files': {$all: [{Name: 'a.txt'},{Name: 'b.txt'},{Name:'c.txt'}], $size: 3}}
my data model is like:
{
"_id": ObjectId("5f0a9c07b001406068c073c1"),
"EmailData" : [
{
"Attachments" : {
"Files" : [
{
"Name" : "a.txt"
},
{
"Name" : "b.txt"
},
{
"Name" : "c.txt"
}
]
}
}
]
}
I have something like this in my mind:
var Filter =
Builders<EmailEntity>.Filter.All(s => s.EmailData????);
or something like:
var Filter =
Builders<EmailEntity>.Filter.ElemMatch(s => s.EmailData???)
I was wondering is there any way in the above filter to use All inside ElemMatch?
The difficulty here is that EmailData.Attachments.Files is an array within another array so C# compiler will get lost when you try to use Expression Trees.
Thankfully there's another approach when you need to define a field using MongoDB .NET driver. You can take advantage of StringFieldDefinition<T> class.
Try:
var files = new[] { new FileData(){ Name = "a.txt"}, new FileData() { Name = "b.txt" }, new FileData() { Name = "c.txt" } };
FieldDefinition<EmailEntity> fieldDef = new StringFieldDefinition<EmailEntity>("EmailData.Attachments.Files");
var filter = Builders<EmailEntity>.Filter.And(
Builders<EmailEntity>.Filter.All(fieldDef, files),
Builders<EmailEntity>.Filter.Size(fieldDef, 3));
var result= collection.Find(filter).ToList();

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.

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.

How to find documents by ObjectId?

I have the following document in a mongodb collection
{
"_id" : "52bbd9bef2ba1f37f4f010c1",
"Name" : "Some Name",
"TypeId" : 1
}
I now want to edit this document using the c# driver
BsonDocument doc = BsonDocument.Parse(json);
IMongoQuery query = Query.And(Query.EQ("_id", doc["_id"]));
UpdateBuilder ub = MongoDB.Driver.Builders.Update.Set('Name', 'New Name');
WriteConcernResult updatedBook = _collection.Update(query, ub);
if (!updatedBook.UpdatedExisting)
{
// I always end here
}
It is also weird that the docs tell that _collection.Update(query, ub) should return a BsonDocument while they return a WriteConcernResult. Anyway if I use another property then _id I find the record.
It seems MongoDB is expecting a ObjectId() function wrapper around a ObjectId, isn't it? At least I need this in my tests while using MongoVUE.
Edit
If I try to find a record with this query
{
"_id" : "52bbd9bef2ba1f37f4f010c1"
}
I get nothing. If I use this
{
"_id" : ObjectId("52bbd9bef2ba1f37f4f010c1"),
}
it worked. So much for the Javascript way. AFAIK I have two ways to update a record with the native .net driver:
FindAndModifyResult
WriteConcernResult
But both ways expecting a BsonValue as value where ObjectId seems not to be a valid one...
So I tried using
IMongoQuery query = Query.And(Query.EQ("_id", doc["_id"]));
as described above but that is the same like
{
"_id" : "52bbd9bef2ba1f37f4f010c1"
}
So I wonder how to update a document by it's ObjectId?
When using the currently available Nuget published MongoDB driver for .NET, I can confirm that this code as an example works properly:
MongoClient client = new MongoClient(); // connect to localhost
MongoServer server = client.GetServer();
MongoDatabase test = server.GetDatabase("test");
MongoCollection examples = test.GetCollection("examples");
string id = "52bc958ca45026c2ff24f90b";
IMongoQuery query = Query.EQ("_id", ObjectId.Parse(id));
UpdateBuilder ub = Update.Set("Name", "George");
WriteConcernResult updatedBook = examples.Update(query, ub);
Using this collection data:
> db.examples.remove()
> db.examples.insert({Name:"Larry"})
> db.examples.find()
{ "_id" : ObjectId("52bc958ca45026c2ff24f90b"), "Name" : "Larry" }
Then, run the C# code above and check the collection again:
> db.examples.find()
{ "Name" : "George", "_id" : ObjectId("52bc958ca45026c2ff24f90b") }
While the WriteConcernResult class itself isn't a BsonDocument, the Response property contains the response from the command.
I also removed the unnecessary Query.And, as it's doesn't do anything when there's only one condition:
query = { "_id" : ObjectId("52bc958ca45026c2ff24f90b") }
ub = { "$set" : { "Name" : "George" } }

Categories

Resources