C# Driver
- offizielle Bibliothek für C#-Anwendungen
- ermöglicht Interaktion mit MongoDB-Datenbanken
Grundlagen für C#-Anwendung mit MongoDB C# Driver
Installation
Überprüfung:
dotnet --list-sdks
Installation:
sudo apt-get update
sudo apt-get install -y dotnet-sdk-8.0
Projekt erstellen
Konsolenprojekt:
dotnet new console --name MongoDBApp --framework net8.0
Web-API-Projekt:
dotnet new web --name WebApi --framework net8.0
MongoDB-Driver zu Projekt hinzufügen
cd projectDir
dotnet add package MongoDB.Driver
Projekt starten
dotnet run
MongoDB-Docker-Container starten
docker run --name mongodb -p:27017:27017 -d frm1971/m165-15
docker run --name mongodb -p:27017:27017 -d mongo
Zugriff auf MongoDB
Verbindung herstellen
MongoClient client = new MongoClient("mongodb://localhost:27017");
Zugriff auf Datenbank
IMongoDatabase database = client.GetDatabase("mydatabase");
Repräsentation von Dokumenten
MongoDB-Datenbank-Dokumente werden in C# als Klassen repräsentiert. Eine solche kann wie folgt aussehen:
class Movie(string title, int year, string summary, List<string> actors)
{
[BsonId]
[BsonRepresentation(BsonType.ObjectId)]
[BsonElement("_id")]
public ObjectId Id { get; set; }
public string Title { get; set; } = title;
public int? Year { get; set; } = year;
public List<string> Actors { get; set; } = actors;
}
Attribut | Bedeutung |
---|---|
BsonId | Id des Dokumentes |
BsonRepresentation(BsonType.<>) | Typ der Eigenschaft |
BsonElement("<elementName>") | Name der Eigenschaft des MongoDB-Dokumentes |
Zugriff auf Collection
Die MongoDB-Collection wird in C# als IMongoCollection<T>
repräsentiert,
wobei T
die Repräsentationsklasse bzw. der Typ des Dokuments ist.
IMongoCollection<Movie> movies = _database.GetCollection<Movie>("movies");
Beispiel
class MovieService : IMovieService
{
private static readonly string CONNECTION = "mongodb://localhost:27017";
private static readonly string DATABASE_NAME = "mydatabase";
private static readonly string MOVIE_COLLECTION_NAME = "movies";
private readonly MongoClient _client;
private readonly IMongoDatabase _database;
private readonly IMongoCollection<Movie> _movies;
public MovieService()
{
_client = new MongoClient(CONNECTION);
_database = _client.GetDatabase(DATABASE_NAME);
_movies = _database.GetCollection<Movie>(MOVIE_COLLECTION_NAME);
}
Allgemeine Befehle
Datenbanken ermitteln
List<string> databaseNames = _client.ListDatabaseNames().ToList();
Collections ermitteln
List<string> collectionNames = _database.ListCollectionNames().ToList();
CRUD-Operationen (sync)
Create
InsertOne()
Restaurant newRestaurant = new() { Name = "Best Pizza", ... };
_restaurantsCollection.InsertOne(newRestaurant);
Nachdem das Dokument in die Collection eingefügt wurde,
wird das _id
-Feld von der Datenbank automatisch in das übergebene Objekt geschrieben.
Dies passiert jedoch nur, wenn das C#-Objekt ein Feld vom Typ ObjectId
oder String
mit dem Attribut [BsonId]
enthält.
Siehe Repräsentation von Dokumenten
und StackOverflow - Get _id of an inserted document in MongoDB?.
InsertMany()
List<Restaurant> newRestaurants = [
new() { Name = "Best Pizza", ... },
new() { Name = "Sushi Place", ... }
];
_restaurantsCollection.InsertMany(newRestaurants);
Read
Folgende Möglichkeiten gibt es, um das Ergebnis zu erhalten:
Methode | Rückgabe |
---|---|
FirstOrDefault() | erstes Dokument oder null , wenn kein Dokument gefunden wurde |
ToList() | alle gefundenen Dokumente als Liste |
ToCursor() | Cursor, um über alle Elemente zu iterieren |
... | ... |
Variante 1: Find mit Filter
var filter = Builders<Restaurant>.Filter
.Eq(r => r.Name, "Bagels N Buns");
Restaurant restaurant = _restaurantsCollection
.Find(filter)
.ToList();
Alle Dokumente können mit einem leeren Filter zurückgegeben werden:
var filter = Builders<Restaurant>.Filter.Empty;
List<Restaurant> restaurants = _restaurantsCollection
.Find(filter)
.ToList();
Variante 2: Find mit Query
List<Restaurant> restaurants = _restaurantsCollection
.Find(r => r.Name == "Bagels N Buns" && r.City == "New York")
.ToList();
Variante 3: Find mit LINQ
var result = _restaurantsCollection.AsQueryable()
.Where(r => r.Name == "Bagels N Buns")
.FirstOrDefault();
oder
var builder = Builders<Flower>.Filter;
var filter = builder.Lt("Price", 20) & builder.Eq("Category", "Perennial");
var query = collection.AsQueryable()
.Where(f => filter.Inject());
oder
var result = from r in _restaurantsCollection.AsQueryable()
where r.Name == "Bagels N Buns"
select r;
Links:
Weitere Befehle
Dokumente zählen:
var count = _restaurantsCollection.Find(filter).CountDocuments();
Duplikate herausfiltern:
var restaurants = _restaurantsCollection
.Distinct(r => r.Cuisine, filter);
Ergebnisse begrenzen:
var restaurants = _restaurantsCollection.Find(filter).Limit(3).ToList();
Ergebnisse überspringen:
var restaurants = _restaurantsCollection.Find(filter).Skip(2).ToList();
Sortierung:
var restaurants = _restaurantsCollection.Find(filter)
.SortBy(r => r.Name).ToList();
Projection (Auswahl von Feldern):
var projection = Builders<Restaurant>.Projection
.Include(restaurant => restaurant.Name)
.Include(restaurant => restaurant.Borough)
.Exclude(restaurant => restaurant.Id);
var restaurants = _restaurantsCollection.Find(filter).Project(projection).ToList();
Update
// filter for the document(s) to update
var filter = Builders<Restaurant>.Filter
.Eq(restaurant => restaurant.Name, "Bagels N Buns");
// update definition
var update = Builders<Restaurant>.Update
.Set(restaurant => restaurant.Name, "2 Bagels 2 Buns");
// update one or all filtered documents
UpdateResult result1 = _restaurantsCollection.UpdateOne(filter, update);
UpdateResult result2 = _restaurantsCollection.UpdateMany(filter, update);
Replace:
var replaceResult = _restaurantsCollection.ReplaceOne(filter, newPizzaRestaurant);
var replaceResult = _restaurantsCollection.ReplaceMany(filter, newPizzaRestaurant);
UpdateResult
MongoDB C# Driver API Reference - Class Update Result
Updates geben immer ein UpdateResult
-Objekt zurück, das Informationen über die durchgeführte Aktualisierung enthält.
Property | Bedeutung |
---|---|
MatchedCount | Anzahl der gefilterten Dokumente |
ModifiedCount | Anzahl der geänderten Dokumente |
... | ... |
Delete
// filter for the document(s) to delete
var filter = Builders<Restaurant>.Filter
.Eq(r => r.Name, "Ready Penny Inn");
// delete one or all filtered documents
DeleteResult result1 = _restaurantsCollection.DeleteOne(filter);
DeleteResult result2 = _restaurantsCollection.DeleteMany(filter);
Builders<T>
Builders<T>
ist eine Hilfsklasse, die das Erstellen von Filtern, Updates und Sortierungen vereinfacht.
Sie bietet statische Methoden, um Filter, Updates und Sortierungen zu erstellen.
Links:
- MongoDB Docs - C#/.NET Driver - Operations with Builders
- MongoDB C# Driver API Reference - Class Builders
Filter
Erstellung:
var builder = Builders<Movie>.Filter;
Vergleichs-Operatoren:
builder.Eq(m => m.Title, "Star Wars");
builder.Ne(m => m.Title, "Star Wars");
builder.Gt(m => m.Year, 1985);
builder.Lt(m => m.Year, 2000);
builder.Gte(m => m.Year, 1985);
builder.Lte(m => m.Year, 2000);
// or with string-based field names
builder.Eq("Title", "Star Wars");
builder.Gt("Year", 1985);
logische Operatoren:
var filter1 = builder.And(
builder.Gte(m => m.Year, 1985),
builder.Ne(m => m.Name, "Kiesel am Strand")
);
// is identical with
var filter2 = builder.Gte(m => m.Year, 1985) & builder.Ne(m => m.Name, "Kiesel am Strand");
Array-Operatoren:
// if array contains one element which matches one condition
builder.Eq("Actors", "Actor One");
builder.Lt(doc -> doc.Numbers, 20);
builder.Gt(doc -> doc.Numbers, 20);
// ...
// if array contains one element which matches all conditions
Builders<BsonDocument>.Filter
.ElemMatch<BsonValue>("Numbers", new BsonDocument { { "$gt", 22 }, { "$lt", 30 } });
builder.All(m => m.Actors, new[] { "Mark Hamill", "Harrison Ford" });
builder.ElemMatch(m => m.Actors, new[] { "Mark Hamill", "Harrison Ford" });
// if array has exactly n elements
builder.Size(m => m.Actors, 3);
Weitere Operatoren:
builders.Exists(m => m.Actors);
builders.Regex(m => m.Title, "^Star Wars");
Sort
var builder = Builders<Flower>.Sort;
var sort = Builders<Flower>.Sort
.Ascending(f => f.Price)
.Descending(f => f.Category);
Update
var builder = Builders<Flower>.Update;
var update = builder
.Set(f => f.SunRequirement, "Full sun")
.Unset(f => f.WaterRequirement)
.Mul(f => f.Price, 0.9);
Methode | MongoDB-Operator | Beschreibung |
---|---|---|
Set(m => m.Title, "New Title") | $set | setzt Wert eines Feldes oder fügt Feld hinzu |
Unset(m => m.Genre | $unset | entfernt Feld |
Inc(m => m.Views, 8) | $inc | erhöht/verringert Wert eines numerischen Feldes |
Mul(m => m.Price, 5) | $mul | multipliziert Wert eines numerischen Feldes mit Faktor |
Rename(m => m.Summary, "Plot") | $rename | benennt vorhandenes Feld um |
Push(m => m.Actors, "Emma Watson") | $push | fügt Element zu Array-Feld hinzu oder erstellt Array |
AddToSet(m => m.Actors, "Emma Watson") | $addToSet | fügt Element zu Array-Feld hinzu, falls es noch nicht existiert (verhindert Duplikate) |
PopFirst(m => m.Actors) | $pop (-1) | entfernt erstes Element aus Array-Feld |
PopLast(m => m.Actors) | $pop (1) | entfernt letztes Element aus Array-Feld |
Pull(m => m.Actors, "Tom Hanks") | $pull | entfernt alle Instanzen eines angegebenen Wertes aus Array-Feld |
PullAll(m => m.Actors, new [] {"Brad Pitt", "Angelina Jolie"}) | $pullAll | entfernt alle Instanzen aller angegebenen Wertes aus Array-Feld |
CurrentDate(m => m.LastUpdated) | $currentDate | setzt Wert eines Feldes auf aktuelles Datum und Uhrzeit (Date/Timestamp) |
Min(m => m.LowestPrice, 12) | $min | aktualisiert Wert eines Feldes nur, wenn neue Wert kleiner ist als der aktuelle Wert |
Max(m => m.HighestRating, 9.5) | $max | aktualisiert Wert eines Feldes nur, wenn neue Wert grösser ist als der aktuelle Wert |
SetOnInsert(m => m.CreatedAt) | $setOnInsert | setzt Wert eines Feldes nur, wenn Update-Operation ein neues Dokument einfügt (siehe hier) |
Combine(update1, update2) | C#-spezifisch | ermöglicht Senden von mehreren Update-Operatoren in einziger Update-Anfrage an Datenbank |
new EmptyPipelineDefinition<Movie>().AppendStage<Movie, Movie, Movie>("{ $set:{...}}"); | Update-Aggregations-Pipelines | ermöglicht Verwendung von Aggregations-Pipelines innerhalt einer Update-Operation |
Beispiele
SetOnInsert()
:
// set 'CreatedAt' only when inserting a new document (Upsert)
var filter = Builders<Movie>.Filter.Eq(m => m.Title, "Ein brandneuer Film");
var update = Builders<Movie>.Update
.Set(m => m.Year, 2024)
.SetOnInsert(m => m.CreatedAt, DateTime.UtcNow);
var options = new UpdateOptions { IsUpsert = true };
await _moviesCollection.UpdateOneAsync(filter, update, options);
Indexe
var index = Builders<Restaurant>.IndexKeys
.Ascending(r => r.Cuisine);
_restaurantsCollection.Indexes
.CreateOne(new CreateIndexModel<Restaurant>(index));