MongoDB.Driver для C# (.NET): полное руководство
1. Что это и зачем нужна
MongoDB.Driver — это официальный, высокопроизводительный и асинхронный драйвер для взаимодействия приложений на платформе .NET (C#, F#, VB.NET) с базой данных MongoDB. Он предоставляет полный набор инструментов для выполнения всех операций CRUD (Create, Read, Update, Delete), управления индексами, агрегации данных, работы с транзакциями и обработки изменений в реальном времени (Change Streams). Драйвер разрабатывается и поддерживается компанией MongoDB Inc., что гарантирует его полную совместимость с последними версиями MongoDB и реализацию всех современных возможностей СУБД.
Зачем нужна эта библиотека? Если вы разрабатываете .NET-приложение (веб-сервис на ASP.NET Core, десктопное приложение на WPF, консольную утилиту или микросервис) и хотите использовать MongoDB в качестве основного или вспомогательного хранилища данных, вам необходим драйвер для установления соединения и обмена данными. MongoDB.Driver абстрагирует сложность сетевого протокола MongoDB (Wire Protocol), предоставляя разработчику удобный, строго типизированный API. Вы работаете с C#-объектами, а драйвер автоматически сериализует их в BSON (двоичный формат MongoDB) и обратно. Это позволяет писать лаконичный, безопасный и производительный код, не вникая в детали низкоуровневого взаимодействия.
Библиотека поддерживает две основные парадигмы работы: синхронную и асинхронную (рекомендуемую). Асинхронные методы (с суффиксом Async) позволяют не блокировать потоки выполнения, что критически важно для масштабируемых серверных приложений. Драйвер также включает в себя LINQ-провайдер, который транслирует LINQ-запросы в синтаксис MongoDB Aggregation Pipeline, что делает код еще более декларативным и привычным для .NET-разработчиков.
2. Установка
Установка производится через менеджер пакетов NuGet. Выполните одну из следующих команд в консоли диспетчера пакетов (Package Manager Console) или в терминале .NET CLI.
Через .NET CLI (рекомендуется):
dotnet add package MongoDB.Driver
Через Package Manager Console (Visual Studio):
Install-Package MongoDB.Driver
Для проектов, использующих Entity Framework Core (опционально):
Существует отдельный провайдер MongoDB.EntityFrameworkCore, но для большинства задач достаточно основного драйвера.
После установки в файл проекта (.csproj) будет добавлена ссылка:
<PackageReference Include="MongoDB.Driver" Version="2.25.0" />
3. Быстрый старт — минимальный рабочий пример
Следующий код подключается к локальному экземпляру MongoDB, получает базу данных "testdb", коллекцию "users", вставляет один документ и выводит его ID в консоль.
using MongoDB.Bson;
using MongoDB.Driver;
// 1. Создаем клиент (подключение к серверу)
var client = new MongoClient("mongodb://localhost:27017");
// 2. Получаем базу данных (создается автоматически, если не существует)
var database = client.GetDatabase("testdb");
// 3. Получаем коллекцию (создается автоматически при первой вставке)
var collection = database.GetCollection<BsonDocument>("users");
// 4. Создаем документ
var document = new BsonDocument
{
{ "name", "Alice" },
{ "age", 30 },
{ "city", "New York" }
};
// 5. Вставляем документ (асинхронно)
await collection.InsertOneAsync(document);
// 6. Выводим сгенерированный ID
Console.WriteLine($"Документ вставлен с ID: {document["_id"]}");
// 7. Читаем все документы из коллекции
var allUsers = await collection.Find(new BsonDocument()).ToListAsync();
foreach (var user in allUsers)
{
Console.WriteLine(user.ToJson());
}
4. Основные методы/функции/классы
4.1 MongoClient
Сигнатура: public MongoClient(string connectionString)
Что делает: Создает экземпляр клиента для подключения к кластеру MongoDB. Connection string содержит адрес сервера, параметры аутентификации и настройки пула соединений.
var client = new MongoClient("mongodb://user:password@localhost:27017/admin?retryWrites=true");
var database = client.GetDatabase("production");
4.2 IMongoDatabase.GetCollection
Сигнатура: IMongoCollection<TDocument> GetCollection<TDocument>(string name, MongoCollectionSettings settings = null)
Что делает: Возвращает объект коллекции, типизированный указанным типом TDocument. Если коллекция не существует, она будет создана автоматически при первой записи в нее.
// Работа с типизированными документами
public class Product
{
public ObjectId Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
}
var collection = database.GetCollection<Product>("products");
4.3 IMongoCollection.InsertOneAsync
Сигнатура: Task InsertOneAsync(TDocument document, InsertOneOptions options = null, CancellationToken cancellationToken = default)
Что делает: Асинхронно вставляет один документ в коллекцию. Если документ не содержит поле _id, драйвер автоматически сгенерирует ObjectId.
var product = new Product { Name = "Laptop", Price = 1200.50m };
await collection.InsertOneAsync(product);
Console.WriteLine($"Inserted product with ID: {product.Id}");
4.4 IMongoCollection.Find
Сигнатура: IFindFluent<TDocument, TProjection> Find(FilterDefinition<TDocument> filter, FindOptions options = null)
Что делает: Выполняет поиск документов, соответствующих заданному фильтру. Возвращает объект IFindFluent, который можно дополнительно настроить (сортировка, проекция, лимит) и затем материализовать вызовом ToListAsync, FirstOrDefaultAsync и т.д.
// Поиск всех продуктов дороже 1000
var filter = Builders<Product>.Filter.Gt(p => p.Price, 1000);
var expensiveProducts = await collection.Find(filter).ToListAsync();
// Поиск одного продукта по имени
var laptop = await collection.Find(p => p.Name == "Laptop").FirstOrDefaultAsync();
4.5 IMongoCollection.ReplaceOneAsync
Сигнатура: Task<ReplaceOneResult> ReplaceOneAsync(FilterDefinition<TDocument> filter, TDocument replacement, ReplaceOptions options = null, CancellationToken cancellationToken = default)
Что делает: Заменяет первый документ, соответствующий фильтру, на новый документ. Поле _id заменяемого документа сохраняется, если оно не указано явно в новом документе.
var filter = Builders<Product>.Filter.Eq(p => p.Name, "Laptop");
var updatedProduct = new Product { Name = "Gaming Laptop", Price = 2000.00m };
var result = await collection.ReplaceOneAsync(filter, updatedProduct);
Console.WriteLine($"Matched: {result.MatchedCount}, Modified: {result.ModifiedCount}");
4.6 IMongoCollection.UpdateOneAsync / UpdateManyAsync
Сигнатура: Task<UpdateResult> UpdateOneAsync(FilterDefinition<TDocument> filter, UpdateDefinition<TDocument> update, UpdateOptions options = null, CancellationToken cancellationToken = default)
Что делает: Обновляет поля существующего документа (документов) без замены всего документа. UpdateOneAsync обновляет первый найденный, UpdateManyAsync — все соответствующие фильтру.
// Увеличить цену всех продуктов на 10%
var filter = Builders<Product>.Filter.Empty;
var update = Builders<Product>.Update.Mul(p => p.Price, 1.10m);
var result = await collection.UpdateManyAsync(filter, update);
Console.WriteLine($"Modified {result.ModifiedCount} documents");
4.7 IMongoCollection.DeleteOneAsync / DeleteManyAsync
Сигнатура: Task<DeleteResult> DeleteOneAsync(FilterDefinition<TDocument> filter, CancellationToken cancellationToken = default)
Что делает: Удаляет один или несколько документов, соответствующих фильтру. DeleteOneAsync удаляет первый найденный документ, DeleteManyAsync — все.
// Удалить все продукты дешевле 100
var filter = Builders<Product>.Filter.Lt(p => p.Price, 100);
var result = await collection.DeleteManyAsync(filter);
Console.WriteLine($"Deleted {result.DeletedCount} documents");
4.8 IMongoCollection.Aggregate
Сигнатура: IAggregateFluent<TResult> Aggregate(PipelineDefinition<TDocument, TResult> pipeline, AggregateOptions options = null)
Что делает: Выполняет конвейер агрегации (Aggregation Pipeline) для сложной обработки данных: группировка, сортировка, преобразование, вычисление статистик.
// Группировка продуктов по имени и подсчет среднего возраста
var pipeline = collection.Aggregate()
.Group(new BsonDocument
{
{ "_id", "$name" },
{ "avgPrice", new BsonDocument("$avg", "$price") },
{ "count", new BsonDocument("$sum", 1) }
})
.Sort(new BsonDocument("avgPrice", -1));
var results = await pipeline.ToListAsync();
foreach (var result in results)
{
Console.WriteLine(result.ToJson());
}
4.9 IMongoDatabase.CreateCollectionAsync
Сигнатура: Task CreateCollectionAsync(string name, CreateCollectionOptions options = null, CancellationToken cancellationToken = default)
Что делает: Явно создает коллекцию с заданными параметрами (например, с указанием размера для capped collection, настройками валидации схемы).
var options = new CreateCollectionOptions
{
Capped = true,
MaxSize = 1024 * 1024, // 1 MB
MaxDocuments = 1000
};
await database.CreateCollectionAsync("logs", options);
4.10 IMongoCollection.Indexes.CreateOneAsync
Сигнатура: Task<string> CreateOneAsync(CreateIndexModel<TDocument> model, CreateOneIndexOptions options = null, CancellationToken cancellationToken = default)
Что делает: Создает индекс на коллекции для ускорения запросов. Можно создавать составные, уникальные, текстовые и геопространственные индексы.
// Создать уникальный индекс по полю Name
var indexModel = new CreateIndexModel<Product>(
Builders<Product>.IndexKeys.Ascending(p => p.Name),
new CreateIndexOptions { Unique = true }
);
await collection.Indexes.CreateOneAsync(indexModel);
5. Реальный практический пример (100-200 строк кода)
Разработаем простую консольную программу для управления каталогом книг в библиотеке. Программа будет поддерживать добавление, поиск, обновление и удаление книг, а также вывод статистики по жанрам.
using MongoDB.Bson;
using MongoDB.Driver;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
public class Book
{
public ObjectId Id { get; set; }
public string Title { get; set; }
public string Author { get; set; }
public string Genre { get; set; }
public int Year { get; set; }
public decimal Price { get; set; }
public bool IsAvailable { get; set; } = true;
}
public class LibraryManager
{
private readonly IMongoCollection<Book> _books;
public LibraryManager(string connectionString, string databaseName, string collectionName)
{
var client = new MongoClient(connectionString);
var database = client.GetDatabase(databaseName);
_books = database.GetCollection<Book>(collectionName);
// Создаем индексы для ускорения поиска
var indexKeys = Builders<Book>.IndexKeys.Ascending(b => b.Author).Ascending(b => b.Genre);
var indexModel = new CreateIndexModel<Book>(indexKeys);
_books.Indexes.CreateOneAsync(indexModel).Wait();
}
public async Task AddBookAsync(Book book)
{
await _books.InsertOneAsync(book);
Console.WriteLine($"Книга '{book.Title}' добавлена с ID: {book.Id}");
}
public async Task<List<Book>> SearchByAuthorAsync(string author)
{
var filter = Builders<Book>.Filter.Regex(b => b.Author, new BsonRegularExpression(author, "i"));
return await _books.Find(filter).ToListAsync();
}
public async Task<List<Book>> SearchByGenreAsync(string genre)
{
var filter = Builders<Book>.Filter.Eq(b => b.Genre, genre);
return await _books.Find(filter).ToListAsync();
}
public async Task<bool> UpdatePriceAsync(ObjectId bookId, decimal newPrice)
{
var filter = Builders<Book>.Filter.Eq(b => b.Id, bookId);
var update = Builders<Book>.Update.Set(b => b.Price, newPrice);
var result = await _books.UpdateOneAsync(filter, update);
return result.ModifiedCount > 0;
}
public async Task<bool> DeleteBookAsync(ObjectId bookId)
{
var filter = Builders<Book>.Filter.Eq(b => b.Id,