MongoDB c# using new driver - c#

I know I may sound to you guys like a total nob but I am.
I am trying to use the mongodb driver in c#. Try to do something like add a record.
I learned today all basic mongodb queries and even tried it with robomongo.
But i don't understand how to use it in c#?
how to call it from the main function??
this is the code I wrote (trying to use mongodb website tutorial):
what is await? what is Task? what does it mean and how to make it work?
Thank you a lot for helping me.
class Program
{
protected static IMongoClient _client;
protected static IMongoDatabase _database;
public static void Main()
{
_client = new MongoClient();
_database = _client.GetDatabase("test");
Task simpleTask = Tasky();
}
public async Task Tasky()
{
var document = new BsonDocument
{
{ "address" , new BsonDocument
{
{ "street", "2 Avenue" },
{ "zipcode", "10075" },
{ "building", "1480" },
{ "coord", new BsonArray { 73.9557413, 40.7720266 } }
}
},
{ "borough", "Manhattan" },
{ "cuisine", "Italian" },
{ "grades", new BsonArray
{
new BsonDocument
{
{ "date", new DateTime(2014, 10, 1, 0, 0, 0, DateTimeKind.Utc) },
{ "grade", "A" },
{ "score", 11 }
},
new BsonDocument
{
{ "date", new DateTime(2014, 1, 6, 0, 0, 0, DateTimeKind.Utc) },
{ "grade", "B" },
{ "score", 17 }
}
}
},
{ "name", "Vella" },
{ "restaurant_id", "41704620" }
};
var collection = _database.GetCollection<BsonDocument>("restaurants");
await collection.InsertOneAsync(document);
}
}

Try to understand simpler version, then read about async/await. Add some documents to your collection using mongo shell and try this:
var collection = new MongoClient("mongodb://localhost").GetServer()
.GetDatabase("your_db").GetCollection<BsonDocument>("your_collection");
var cursor = collection.FindAll();
foreach(var doc in cursor) {
Console.WriteLine(doc);
}
cursor is used to get documents one by one.

Related

Dictionary with tuples values returning null?

I have a class with a dictionary defined as a private member :
Dictionary<int, (string, string)> arenaIdToSetAndNumber = new Dictionary<int, (string, string)>()
{
{ 70506, ("c16", "337") },
{ 70507, ("c16", "340") },
{ 70508, ("c16", "343") },
{ 70509, ("c16", "346") },
{ 70510, ("c16", "349") },
};
While debugging, I get to an item corresponding to key 70506, I see this with 2 watches:
I try doing var test = arenaIdToSetAndNumber[c.grpId].Item1 and test is set to null just as seen in the second watch! I don't understand why
The debugger and the watcher are not able to infer what is Item1 from the indexer operator [], thus will give you null in the watch. But once you run the code, it will just work fine for reading purpose. For writing purpose instead, you need to take out the whole tuple, edit it and reinsert in the dictionary:
static void Main(string[] args)
{
Dictionary<int, (string, string)> arenaIdToSetAndNumber = new Dictionary<int, (string, string)>()
{
{ 70506, ("c16", "337") },
{ 70507, ("c16", "340") },
{ 70508, ("c16", "343") },
{ 70509, ("c16", "346") },
{ 70510, ("c16", "349") },
};
var myTuple = arenaIdToSetAndNumber[70509];
myTuple.Item1 = "c18";
arenaIdToSetAndNumber[70509] = myTuple;
//System.Console.WriteLine(arenaIdToSetAndNumber[70509].Item1); // This prints c18
}
Otherwise, in one line, just recreate the whole tuple:
arenaIdToSetAndNumber[70509] = ("c18", arenaIdToSetAndNumber[70509].Item2);
All of this because the ValueTuple is a struct. Similar question here
This does not use tuples but solves your problem. Since you want to read the values create an immutable class, use properties to retrive the values.
public class Contents
{
private readonly string leftValue;
private readonly string rightValue;
public Contents(string aLeftValue, string aRightValue)
{
leftValue = aLeftValue;
rightValue = aRightValue;
}
public string LeftValue => leftValue;
public string RightValue => rightValue;
}
Modify your code to use the new class.
Dictionary<int, Contents> arenaIdToSetAndNumber = new Dictionary<int, Contents>()
{
{ 70506, new Contents("c16", "337") },
{ 70507, new Contents("c16", "340") },
{ 70508, new Contents("c16", "343") },
{ 70509, new Contents("c16", "346") },
{ 70510, new Contents("c16", "349") },
};
And you can test it with this.
var content = arenaIdToSetAndNumber[70506];
string leftValue = content.LeftValue;
string rightValue = content.RightValue;
Hope this solves your problem.

how to replace the entire array using MongoDB c# driver

Say, the existing document in DB is like this:
{
"_id": "1",
"settings": {
"languages": [ "english", "french" ]
}
}
Now I want to update the document to this:
{
"_id": "1",
"settings": {
"languages": [ "korean", "german" ]
}
}
I tired this following code:
var lan = new List<string> { "finish", "russian", "korean" }
collection.UpdateOne(
Builders<MyObject>.Filter.Eq("_id", "1"),
Builders<MyObject>.Update.Set("settings.languages", lan));
But got following exception:
MongoDB.Bson.Serialization.Serializers.EnumerableInterfaceImplementerSerializer2[System.Collections.Generic.List1[System.String],System.String]' cannot be converted to type 'MongoDB.Bson.Serialization.IBsonSerializer`1[System.String]
I also tried using BsonArray to initialize the new languages array:
var bsonArray = new BsonArray
{
"korean",
"german"
};
collection.UpdateOne(
Builders<MyObject>.Filter.Eq("_id", "1"),
Builders<MyObject>.Update.Set("settings.languages", bsonArray));
The update could be executed without error, but the languages in document is changed to:
{
"_id": "1",
"settings": {
"languages": "[korean, german]"
}
}
It becomes "[ xx, xx ]", instead of [ "xx", "xx" ]. It is not what I expected.
You're getting that error message because you're using strongly typed builders on type MyObject which probably looks more or less like below:
public class MyObject
{
public string _id { get; set; }
public Settings settings { get; set; }
}
public class Settings
{
public string[] languages { get; set; }
}
So since you have a strongly typed Builder you are getting an exception because of the type mismatch between List and Array. Two ways to fix that:
Either use .ToArray() on list to get the same type as the one you have in your MyObject:
var lan = new List<string> { "finish", "russian", "korean" };
collection.UpdateOne(
Builders<MyObject2>.Filter.Eq("_id", "1"),
Builders<MyObject2>.Update.Set("settings.languages", lan.ToArray()));
or skip the type validation using BsonDocument class:
var collection = mydb.GetCollection<BsonDocument>("col");
var lan = new List<string> { "finish", "russian", "korean" };
collection.UpdateOne(
Builders<BsonDocument>.Filter.Eq("_id", "1"),
Builders<BsonDocument>.Update.Set("settings.languages", lan));

Method inside an array in C#

I just got in contact with C# and I was wondering if it's possible to call a method inside an array. I have to say that I'm working with NoSQL database (mongodb).
This is mi code, and I want to call data() method inside that JSON.
static void Main(string[] args)
{
MongoClient client = new MongoClient();
var db = client.GetDatabase("test");
var collection = db.GetCollection<BsonDocument>("collection");
var document = new BsonDocument
{
{ "date", 10/04/2018 },
{ "data", data() }
};
collection.InsertOneAsync(document);
Console.Read();
}
static void data()
{
for (int i = 1; i <= 50; i++)
{
var data = new BsonDocument
{
{ "magnitude"+i, new BsonDocument{
{ "value", 5 }
} }
};
}
}
EDIT: Basically, what I'm trying to create with C# is this json below. I already did it with PHP and now, I'm trying to do it with C#.
{
"_id" : ObjectId("5abb735eb57dce214009035a"),
"date" : 1262300400,
"data" : {
"magnitude1" : {
"value" : 60
},
"magnitude2" : {
"value" : 38
},
"magnitude3" : {
"value" : 200
},
"magnitude4" : {
"value" : 62
},
"magnitude5" : {
"value" : 153
},
"magnitude6" : {
"value" : 176
},
"magnitude7" : {
"value" : 185
},
"magnitude8" : {
"value" : 168
},
.
.
.
You can use methods to gather data but I'm not sure exactly how you're asking it. Related to the code example I'll just give a simple run down, which is basic programming in general, not just C#.
You can write methods that return void or that return a variable of some type (at a minimum).
//Returns void
public void DoSomething()
{
//Do some work
return;
}
//Returns int
public int GetSomething()
{
int result = 100;
return result;
}
When you have methods that return data you can use them as you would a variable; just remember the method will execute every time it's called so it's often best to save the data to a variable. But for your example you can do something like this.
//other code ommitted
var document = new BsonDocument
{
{ "date", 10/04/2018 },
{ "data", getDocuments() }
};
//remaining code omitted
static List<BsonDocument> getDocuments()
{
var documents = new List<BsonDocument>();
for (int i = 1; i <= 50; i++)
{
var document = new BsonDocument
{
{ "magnitude" + i, new BsonDocument { { "value", 5 } } }
};
documents.Add(document);
}
return documents;
}
Now I modified the data() method to return a list of documents and changed the naming to match it but I'm not sure what you wanted to do with the method. That was my best assumption of what you were trying to accomplish by looking at your code so feel free to ignore all of it if it's wrong.
I've could solve it thanks to #Michael .Code below in case helps to anyone.
static void Main(string[] args)
{
MongoClient client = new MongoClient();
var db = client.GetDatabase("test");
var collection = db.GetCollection<BsonDocument>("Collection");
var document = new BsonDocument
{
{ "date", 10/04/2018 },
{ "data", new BsonDocument{ getDocuments() } }
};
collection.InsertOneAsync(document);
Console.Read();
}
static BsonDocument getDocuments()
{
var documents = new BsonDocument();
for (int i = 1; i <= 5; i++)
{
var document = new BsonDocument
{
{ "magnitude" + i, new BsonDocument { { "value", 5 } } }
};
documents.AddRange(document);
}
return documents;
}

Using Facets in the Aggregation Framework C#

I would like to create an Aggregation on my data to get the total amount of counts for specific tags for a collection of books in my .Net application.
I have the following Book class.
public class Book
{
public string Id { get; set; }
public string Name { get; set; }
[BsonDictionaryOptions(DictionaryRepresentation.Document)]
public Dictionary<string, string> Tags { get; set; }
}
And when the data is saved, it is stored in the following format in MongoDB.
{
"_id" : ObjectId("574325a36fdc967af03766dc"),
"Name" : "My First Book",
"Tags" : {
"Edition" : "First",
"Type" : "HardBack",
"Published" : "2017",
}
}
I've been using facets directly in MongoDB and I am able to get the results that I need by using the following query:
db.{myCollection}.aggregate(
[
{
$match: {
"Name" : "SearchValue"
}
},
{
$facet: {
"categorizedByTags" : [
{
$project :
{
Tags: { $objectToArray: "$Tags" }
}
},
{ $unwind : "$Tags"},
{ $sortByCount : "$Tags"}
]
}
},
]
);
However I am unable to transfer this over to the .NET C# Driver for Mongo. How can I do this using the .NET C# driver?
Edit - I will ultimately be looking to query the DB on other properties of the books as part of a faceted book listings page, such as Publisher, Author, Page count etc... hence the usage of $facet, unless there is a better way of doing this?
I would personally not use $facet here since you've only got one pipeline which kind of defeats the purpose of $facet in the first place...
The following is simpler and scales better ($facet will create one single potentially massive document).
db.collection.aggregate([
{
$match: {
"Name" : "My First Book"
}
}, {
$project: {
"Tags": {
$objectToArray: "$Tags"
}
}
}, {
$unwind: "$Tags"
}, {
$sortByCount: "$Tags"
}, {
$group: { // not really needed unless you need to have all results in one single document
"_id": null,
"categorizedByTags": {
$push: "$$ROOT"
}
}
}, {
$project: { // not really needed, either: remove _id field
"_id": 0
}
}])
This could be written using the C# driver as follows:
var collection = new MongoClient().GetDatabase("test").GetCollection<Book>("test");
var pipeline = collection.Aggregate()
.Match(b => b.Name == "My First Book")
.Project("{Tags: { $objectToArray: \"$Tags\" }}")
.Unwind("Tags")
.SortByCount<BsonDocument>("$Tags");
var output = pipeline.ToList().ToJson(new JsonWriterSettings {Indent = true});
Console.WriteLine(output);
Here's the version using a facet:
var collection = new MongoClient().GetDatabase("test").GetCollection<Book>("test");
var project = PipelineStageDefinitionBuilder.Project<Book, BsonDocument>("{Tags: { $objectToArray: \"$Tags\" }}");
var unwind = PipelineStageDefinitionBuilder.Unwind<BsonDocument, BsonDocument>("Tags");
var sortByCount = PipelineStageDefinitionBuilder.SortByCount<BsonDocument, BsonDocument>("$Tags");
var pipeline = PipelineDefinition<Book, AggregateSortByCountResult<BsonDocument>>.Create(new IPipelineStageDefinition[] { project, unwind, sortByCount });
// string based alternative version
//var pipeline = PipelineDefinition<Book, BsonDocument>.Create(
// "{ $project :{ Tags: { $objectToArray: \"$Tags\" } } }",
// "{ $unwind : \"$Tags\" }",
// "{ $sortByCount : \"$Tags\" }");
var facetPipeline = AggregateFacet.Create("categorizedByTags", pipeline);
var aggregation = collection.Aggregate().Match(b => b.Name == "My First Book").Facet(facetPipeline);
var output = aggregation.Single().Facets.ToJson(new JsonWriterSettings { Indent = true });
Console.WriteLine(output);

MongoDB c# create role?

I'm trying to create a role with the c# driver.
Can anyone please tell me how to do this?
I tried several things like this:
var command = new CommandDocument(
new BsonDocument
{
{ "createRole", "Testentity_read" },
{ "privileges", new BsonArray(new BsonDocument
{
{
"resource", new BsonDocument
{
{"db", "MyDb"},
{"collection", "Testentity"}
}
},
{
"actions", new BsonArray {"read"}
}
})},
{ "roles", new BsonArray()}
}
);
var result = _database.RunCommand(command);
but always getting this exception:
".NET type MongoDB.Bson.BsonElement cannot be mapped to a BsonValue."
I found out how to create a role from C#-driver.
var command = new CommandDocument
{
{
"createRole", "Testentity_find"
},
{
"privileges", new BsonArray
{
new BsonDocument
{
{
"resource", new BsonDocument
{
{"db", "MyDb"},
{"collection", "Testentity"}
}
},
{
"actions", new BsonArray {"find"}
}
}
}
},
{ "roles", new BsonArray()}
};

Categories

Resources