concat aggregate mongo db driver c# - 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.

Related

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();

C# using projection on MongoDB document

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

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" } }

(mongodb) Fetching a bson object within a bson object using csharp

I have a collection which contains documents like:
{
field1: {subfield1:{ssfield1:5,ssfield2:6},subfield2:6},
field2: 1,
...
}
I'd like to fetch only the subfield, but I'm not sure how to get it querying from csharp (it doesn't seem to return the bsondocument within the bsondocument).
Any help?
I tried this:
String c = "mongodb://"+myip;
MongoServer server = MongoServer.Create(c);
MongoDatabase db = server.GetDatabase(mydb);
var collection = db.GetCollection(col);
string[] fields = new string[] { "field1" };
MongoCursor cursor = collection.Find().SetFields(fields);
but it seems to return
{subfield2:6}
I created a collection with one document very similar to your sample document:
> db.test.find().pretty()
{
"_id" : ObjectId("518ac1aa92f1c388279a9979"),
"field1" : {
"subfield1" : {
"ssfield1" : 5,
"ssfield2" : 6
},
"subfield2" : 6
},
"field2" : 1
}
>
Before showing the result I got when I attempted to reproduce your C# code, let's look at the same query in the MongoDB shell:
> db.test.find({}, { field1 : 1 }).pretty()
{
"_id" : ObjectId("518ac1aa92f1c388279a9979"),
"field1" : {
"subfield1" : {
"ssfield1" : 5,
"ssfield2" : 6
},
"subfield2" : 6
}
}
>
There are several things to notice here:
By default the server always returns the _id field
field1 was the only other field returned (just what we asked for)
subfield2 was returned because it's embedded in field1
I used slightly different C# code from yours to test:
foreach (var document in collection.FindAll().SetFields("field1"))
{
Console.WriteLine(document.ToJson(new JsonWriterSettings { Indent = true }));
}
And the output I got from that loop was:
{
"_id" : ObjectId("518ac1aa92f1c388279a9979"),
"field1" : {
"subfield1" : {
"ssfield1" : 5.0,
"ssfield2" : 6.0
},
"subfield2" : 6.0
}
}
which is essentially identical to the output from the MongoDB shell.
Let me know if you have any further questions.

Categories

Resources