目录
[2. 连接配置](#2. 连接配置)
NET Core 应用程序中使用 MongoDB 有许多好处,尤其是在处理大规模数据、需要高灵活性和扩展性的场景下。
1.添加包
添加 MongoDB.Driver 包。

2. 连接配置
2.1.连接字符串
dbsettings.json文件添加 MongoDB连接配置
cs
//MongoDB配置
"MongoDBSettings": {
"MongoConnStr": "mongodb://root:密码@iP地址:Mongo端口",
"DatabaseName": "数据库名称"
},
2.2.连接类
cs
namespace Frame3_DataRepository.MongoRepository
{
/// <summary>
/// Mongo配置获取
/// </summary>
public class MongoOptions
{
/// <summary>
/// 连接地址
/// </summary>
public string MongoConnStr { get; set; }
/// <summary>
/// 连接数据库
/// </summary>
public string DatabaseName { get; set; }
}
}
案例如下

3.仓储配置
3.1.仓储实现
为MongoDB添加仓储方便使用。
cs
using MongoDB.Bson;
using MongoDB.Driver;
using System.Linq.Expressions;
namespace Frame3_DataRepository.MongoRepository
{
/// <summary>
/// 泛型MongoDB仓储实现类,实现IMongoRepository<T>接口,约束T必须是class类型
/// </summary>
/// <typeparam name="T"></typeparam>
public class MongoRepository<T> : IMongoRepository<T> where T : class
{
// 私有字段,存储MongoDB集合对象
private readonly IMongoCollection<T> _collection;
/// <summary>
/// 构造函数,通过依赖注入初始化
/// </summary>
/// <param name="database">Mongo数据库实例</param>
/// <param name="collectionName">集合名称(可选,默认为类型名称)</param>
public MongoRepository(IMongoDatabase database, string collectionName = null)
{
// 获取或创建集合:如果collectionName为null则使用类型名称作为集合名
_collection = database.GetCollection<T>(collectionName ?? typeof(T).Name);
}
#region 基本CRUD操作
/// <summary>
/// 插入单个文档
/// </summary>
/// <param name="document">要插入的文档</param>
/// <returns>受影响的行数(1表示成功,0表示失败)</returns>
public async Task<int> InsertAsync(T document)
{
try
{
// 异步插入单个文档
await _collection.InsertOneAsync(document);
return 1; // 插入单个文档总是返回1表示成功
}
catch
{
return 0; // 插入失败返回0
}
}
/// <summary>
/// 批量插入文档
/// </summary>
/// <param name="documents">要插入的文档集合</param>
/// <returns>实际插入的文档数量</returns>
public async Task<int> InsertAsync(IEnumerable<T> documents)
{
try
{
// 转换为列表以避免多次枚举
var docsList = documents.ToList();
// 如果集合为空则直接返回0
if (!docsList.Any())
{
return 0;
}
// 异步批量插入文档
await _collection.InsertManyAsync(docsList);
// 返回实际插入的文档数量
return docsList.Count;
}
catch
{
return 0; // 插入失败返回0
}
}
/// <summary>
/// 根据ID获取文档
/// </summary>
/// <param name="id">文档ID字符串</param>
/// <returns>找到的文档或默认值</returns>
public async Task<T> GetByIdAsync(string id)
{
try
{
// 构建ID过滤器(MongoDB默认使用"_id"字段)
var filter = Builders<T>.Filter.Eq("_id", ObjectId.Parse(id));
// 异步查找并返回第一个匹配的文档
return await _collection.Find(filter).FirstOrDefaultAsync();
}
catch
{
return default; // 出错返回默认值
}
}
/// <summary>
/// 获取所有文档
/// </summary>
/// <returns>所有文档列表或默认值</returns>
public async Task<List<T>> GetAllAsync()
{
try
{
// 使用空过滤器获取所有文档
return await _collection.Find(_ => true).ToListAsync();
}
catch
{
return default; // 出错返回默认值
}
}
/// <summary>
/// 条件查询
/// </summary>
/// <param name="filter">LINQ表达式过滤器</param>
/// <returns>匹配条件的文档集合</returns>
public async Task<IEnumerable<T>> FindByConditionAsync(Expression<Func<T, bool>> filter)
{
try
{
// 使用表达式过滤器查询文档
return await _collection.Find(filter).ToListAsync();
}
catch
{
return default; // 出错返回默认值
}
}
/// <summary>
/// 更新单个文档
/// </summary>
/// <param name="filter">查询过滤器</param>
/// <param name="update">更新定义</param>
/// <returns>实际修改的文档数量</returns>
public async Task<int> UpdateAsync(Expression<Func<T, bool>> filter, UpdateDefinition<T> update)
{
try
{
// 异步更新单个文档
var result = await _collection.UpdateOneAsync(filter, update);
// 返回实际修改的文档数量
return (int)result.ModifiedCount;
}
catch
{
return 0; // 出错返回0
}
}
/// <summary>
/// 替换整个文档
/// </summary>
/// <param name="filter">查询过滤器</param>
/// <param name="replacement">替换文档</param>
/// <returns>实际修改的文档数量</returns>
public async Task<int> UpdateAsync(Expression<Func<T, bool>> filter, T replacement)
{
try
{
// 异步替换整个文档
var result = await _collection.ReplaceOneAsync(filter, replacement);
// 返回实际修改的文档数量
return (int)result.ModifiedCount;
}
catch
{
return 0; // 出错返回0
}
}
/// <summary>
/// 删除单个文档
/// </summary>
/// <param name="filter">查询过滤器</param>
/// <returns>实际删除的文档数量</returns>
public async Task<int> DeleteAsync(Expression<Func<T, bool>> filter)
{
try
{
// 异步删除单个文档
var result = await _collection.DeleteOneAsync(filter);
// 返回实际删除的文档数量
return (int)result.DeletedCount;
}
catch
{
return 0; // 出错返回0
}
}
/// <summary>
/// 根据ID删除文档
/// </summary>
/// <param name="id">文档ID</param>
/// <returns>实际删除的文档数量</returns>
public async Task<int> DeleteByIdAsync(string id)
{
try
{
// 构建ID过滤器
var filter = Builders<T>.Filter.Eq("_id", ObjectId.Parse(id));
// 异步删除匹配的文档
var result = await _collection.DeleteOneAsync(filter);
// 返回实际删除的文档数量
return (int)result.DeletedCount;
}
catch
{
return 0; // 出错返回0
}
}
/// <summary>
/// 批量删除文档
/// </summary>
/// <param name="filter">查询过滤器</param>
/// <returns>实际删除的文档数量</returns>
public async Task<int> DeleteManyAsync(Expression<Func<T, bool>> filter)
{
try
{
// 异步删除多个文档
var result = await _collection.DeleteManyAsync(filter);
// 返回实际删除的文档数量
return (int)result.DeletedCount;
}
catch
{
return 0; // 出错返回0
}
}
#endregion
#region 高级操作
/// <summary>
/// 分页查询
/// </summary>
/// <param name="filter">查询过滤器</param>
/// <param name="pageNumber">页码</param>
/// <param name="pageSize">每页大小</param>
/// <param name="sort">排序定义(可选)</param>
/// <returns>包含数据和总数的元组</returns>
public async Task<(List<T> Data, int Total)> PaginateAsync(Expression<Func<T, bool>> filter, int pageNumber, int pageSize, SortDefinition<T> sort = null)
{
try
{
// 获取匹配条件的文档总数
var count = (int)await _collection.CountDocumentsAsync(filter);
// 构建基础查询
var query = _collection.Find(filter);
// 如果提供了排序条件,则应用排序
if (sort != null)
{
query = query.Sort(sort);
}
// 执行分页查询:跳过前面的记录,限制返回数量
var data = await query.Skip((pageNumber - 1) * pageSize)
.Limit(pageSize)
.ToListAsync();
// 返回数据和总数
return (data, count);
}
catch
{
return (null, 0); // 出错返回空数据和0总数
}
}
/// <summary>
/// 聚合查询
/// </summary>
/// <typeparam name="TResult">结果类型</typeparam>
/// <param name="pipeline">聚合管道定义</param>
/// <returns>聚合结果集合</returns>
public async Task<IEnumerable<TResult>> AggregateAsync<TResult>(PipelineDefinition<T, TResult> pipeline)
{
// 异步执行聚合管道并返回结果列表
return await _collection.Aggregate(pipeline).ToListAsync();
}
/// <summary>
/// 创建索引
/// </summary>
/// <param name="keys">索引键定义</param>
/// <param name="options">索引选项(可选)</param>
/// <returns>创建的索引名称</returns>
public async Task<string> CreateIndexAsync(IndexKeysDefinition<T> keys, CreateIndexOptions options = null)
{
// 异步创建索引并返回索引名称
return await _collection.Indexes.CreateOneAsync(new CreateIndexModel<T>(keys, options));
}
/// <summary>
/// 批量操作
/// </summary>
/// <param name="requests">批量写操作模型集合</param>
/// <returns>批量操作结果</returns>
public async Task<BulkWriteResult<T>> BulkWriteAsync(IEnumerable<WriteModel<T>> requests)
{
// 异步执行批量写操作
return await _collection.BulkWriteAsync(requests);
}
/// <summary>
/// 文档计数
/// </summary>
/// <param name="filter">查询过滤器(可选)</param>
/// <returns>匹配条件的文档数量</returns>
public async Task<long> CountAsync(Expression<Func<T, bool>> filter = null)
{
// 根据是否提供过滤器返回相应计数
return filter == null
? await _collection.CountDocumentsAsync(_ => true) // 无过滤器时计算所有文档
: await _collection.CountDocumentsAsync(filter); // 有过滤器时计算匹配文档
}
#endregion
#region 事务支持
/// <summary>
/// 执行事务操作
/// </summary>
/// <param name="actions">要在事务中执行的操作</param>
public async Task ExecuteInTransactionAsync(Func<IClientSessionHandle, IMongoCollection<T>, Task> actions)
{
// 创建会话
using var session = await _collection.Database.Client.StartSessionAsync();
// 开始事务
session.StartTransaction();
try
{
// 执行用户定义的操作
await actions(session, _collection);
// 提交事务
await session.CommitTransactionAsync();
}
catch
{
// 出错时中止事务
await session.AbortTransactionAsync();
throw; // 重新抛出异常
}
}
#endregion
}
}
案例如下

3.2.仓储接口
方便使用仓储给所有实现加接口
cs
using MongoDB.Driver;
using System.Linq.Expressions;
namespace Frame3_DataRepository.MongoRepository
{
public interface IMongoRepository<T> where T : class
{
/// <summary>
/// 插入文档
/// </summary>
/// <param name="document"></param>
/// <returns></returns>
Task<int> InsertAsync(T document);
/// <summary>
/// 批量插入文档
/// </summary>
Task<int> InsertAsync(IEnumerable<T> documents);
/// <summary>
/// 根据ID获取文档
/// </summary>
Task<T> GetByIdAsync(string id);
/// <summary>
/// 获取所有文档
/// </summary>
Task<List<T>> GetAllAsync();
/// <summary>
/// 条件查询
/// </summary>
Task<IEnumerable<T>> FindByConditionAsync(Expression<Func<T, bool>> filter);
/// <summary>
/// 更新单个文档
/// </summary>
Task<int> UpdateAsync(Expression<Func<T, bool>> filter, UpdateDefinition<T> update);
/// <summary>
/// 替换整个文档
/// </summary>
Task<int> UpdateAsync(Expression<Func<T, bool>> filter, T replacement);
/// <summary>
/// 删除单个文档
/// </summary>
Task<int> DeleteAsync(Expression<Func<T, bool>> filter);
/// <summary>
/// 根据ID删除文档
/// </summary>
Task<int> DeleteByIdAsync(string id);
/// <summary>
/// 批量删除文档
/// </summary>
Task<int> DeleteManyAsync(Expression<Func<T, bool>> filter);
/// <summary>
/// 分页查询
/// </summary>
Task<(List<T> Data, int Total)> PaginateAsync(Expression<Func<T, bool>> filter, int pageNumber, int pageSize, SortDefinition<T> sort = null);
/// <summary>
/// 聚合查询
/// </summary>
Task<IEnumerable<TResult>> AggregateAsync<TResult>(PipelineDefinition<T, TResult> pipeline);
/// <summary>
/// 创建索引
/// </summary>
Task<string> CreateIndexAsync(IndexKeysDefinition<T> keys, CreateIndexOptions options = null);
/// <summary>
/// 批量操作
/// </summary>
Task<BulkWriteResult<T>> BulkWriteAsync(IEnumerable<WriteModel<T>> requests);
/// <summary>
/// 文档计数
/// </summary>
Task<long> CountAsync(Expression<Func<T, bool>> filter = null);
/// <summary>
/// 执行事务操作
/// </summary>
Task ExecuteInTransactionAsync(Func<IClientSessionHandle, IMongoCollection<T>, Task> actions);
}
}
案例如下

4.获取配置和注册
获取连接字符串、注册Mongo实例和仓储
4.1.添加配置获取方法
cs
using Microsoft.Extensions.Configuration;
namespace Frame4_LibraryCore.BaseConfig
{
/// <summary>
/// 全局配置
/// </summary>
public static class Config
{
/// <summary>
/// 从指定的 JSON 配置文件中读取配置,并反序列化为指定类型
/// </summary>
/// <typeparam name="T">目标配置类型(如 RedisSettings、DatabaseSettings 等)</typeparam>
/// <param name="fileName">JSON 配置文件名(如 "appsettings.json")</param>
/// <param name="sessions">配置节点名称(如 "RedisSettings")</param>
/// <returns>返回绑定后的强类型配置对象</returns>
public static T GetSetting<T>(string fileName, string sessions)
{
//创建 ConfigurationBuilder 实例,用于构建配置
var builder = new ConfigurationBuilder()
//设置配置文件的基础路径为当前程序运行目录
.SetBasePath(Directory.GetCurrentDirectory())
//添加 JSON 文件作为配置源:
//- fileName: 指定要加载的 JSON 文件
//- optional: false 表示文件必须存在,否则抛出异常
//- reloadOnChange: true 表示文件修改时自动重新加载
.AddJsonFile(fileName, optional: false, reloadOnChange: true);
//构建配置对象(IConfigurationRoot)
IConfigurationRoot config = builder.Build();
//获取指定配置节点(sessions),并将其反序列化为类型 T
var conn = config.GetSection(sessions).Get<T>();
//返回反序列化后的配置对象
return conn;
}
}
}
案例如下

4.2.注册
添加注册方法方便程序注册
cs
using Frame4_LibraryCore.BaseConfig;
using Microsoft.Extensions.DependencyInjection;
using MongoDB.Driver;
namespace Frame3_DataRepository.MongoRepository
{
/// <summary>
/// MongoDB仓储相关服务
/// </summary>
public static class MongoExtension
{
/// <summary>
/// 扩展方法:向IServiceCollection添加MongoDB仓储相关服务
/// </summary>
/// <param name="services">服务集合</param>
/// <returns>配置后的服务集合</returns>
public static IServiceCollection AddMongoRepository(this IServiceCollection services)
{
// 从配置文件"dbsettings.json"的"MongoDBSettings"节点获取MongoDB配置选项
var mongoOptions = Config.GetSetting<MongoOptions>("dbsettings.json", "MongoDBSettings");
// 注册IMongoClient为单例服务(因为MongoClient是线程安全的,适合单例)
services.AddSingleton<IMongoClient>(sp => new MongoClient(mongoOptions.MongoConnStr));
// 注册IMongoDatabase为作用域服务(每个请求一个实例)
services.AddScoped(sp =>
{
// 从服务容器获取已注册的IMongoClient实例
var client = sp.GetRequiredService<IMongoClient>();
// 使用配置中的数据库名称获取数据库实例
return client.GetDatabase(mongoOptions.DatabaseName);
});
// 注册泛型仓储接口和实现(IMongoRepository<>和MongoRepository<>)
services.AddScoped(typeof(IMongoRepository<>), typeof(MongoRepository<>));
// 返回配置好的服务集合以支持链式调用
return services;
}
}
}
案例如下

新增好注册方法后即可在 Program 或 Startup 中注册。
cs
//注册MongoDB服务
builder.Services.AddMongoRepository();
案例如下

5.常规使用案例
下面是 实体、实现、接口和控制器的使用案例
5.1实体
cs
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;
namespace Frame2_DataModel.MongoEntity.Product
{
/// <summary>
/// 产品表-Mongo
/// </summary>
public class ProductEntity
{
[BsonId] // 标记这是 MongoDB 的 _id 字段
[BsonRepresentation(BsonType.ObjectId)] // 表示该字段使用 ObjectId 类型
public string Id { get; set; }
/// <summary>
/// 产品名称
/// </summary>
public string ProductName { get; set; }
/// <summary>
/// 价格
/// </summary>
public decimal Price { get; set; }
/// <summary>
/// 库存
/// </summary>
public int Stock { get; set; }
}
}
案例如下

5.2.实现
cs
using Frame_Service.IService.Product;
using Frame1_Service.IService.Product;
using Frame2_DataModel.MongoEntity.Product;
using Frame3_DataRepository.MongoRepository;
using Frame6_LibraryUtility;
namespace Frame1_Service.Service.Product
{
/// <summary>
/// MongoDB测试实现
/// </summary>
public class ProductSvr : BaseService, IProductSvr
{
/// <summary>
/// 产品-Mongo
/// </summary>
private readonly IMongoRepository<ProductEntity> _productSvr;
/// <summary>
/// 构造函数
/// </summary>
public ProductSvr(IMongoRepository<ProductEntity> productSvr)
{
_productSvr = productSvr;
}
#region 查询数据
/// <summary>
/// 获取所有产品
/// </summary>
/// <returns></returns>
public async Task<ResultModel<List<ProductEntity>>> GetProductAll()
{
var result = new ResultModel<List<ProductEntity>>() { Data = null };
var list = await _productSvr.GetAllAsync();
result.Code = ResultCodeEnum.Success;
result.Msg = "获取成功";
result.Data = list;
return result;
}
/// <summary>
/// 根据Id获取产品
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public async Task<ResultModel<ProductEntity>> GetByIdProduct(string id)
{
var result = new ResultModel<ProductEntity>() { Data = null };
var list = await _productSvr.GetByIdAsync(id);
result.Msg = "获取成功";
result.Data = list;
return result;
}
/// <summary>
/// 获取所有产品-分页
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
public async Task<ResultPageModel<List<ProductEntity>>> GetProductPageList(PageList model)
{
var result = new ResultPageModel<List<ProductEntity>>() { Data = null };
var (products, total) = await _productSvr.PaginateAsync(filter: p => true, pageNumber: model.PageIndex, pageSize: model.PageSize);
result.TotalCount = total;
result.PageIndex = model.PageIndex;
result.PageSize = model.PageSize;
result.Data = products;
result.Msg = "获取成功";
return result;
}
#endregion
#region 修改数据
/// <summary>
/// 保存产品
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
public async Task<ResultModel<int>> SaveProduct(ProductEntity model)
{
var result = new ResultModel<int>() { Data = 0 };
#region 数据校验
if (model.IsEmpty())
{
result.Code = ResultCodeEnum.Error;
result.Msg = "传参错误";
return result;
}
#endregion
int row = 0;
if (model.Id.IsEmpty())
{
row = await _productSvr.InsertAsync(model);
}
else
{
row = await _productSvr.UpdateAsync(a => a.Id.Equals(model.Id), model);
}
if (row > 0)
{
result.Code = ResultCodeEnum.Success;
result.Msg = "操作成功";
result.Data = row;
}
return result;
}
/// <summary>
/// 根据Id删除产品
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public async Task<ResultModel<int>> RemoveProduct(string id)
{
var result = new ResultModel<int>() { Data = 0 };
int row = await _productSvr.DeleteByIdAsync(id);
if (row > 0)
{
result.Code = ResultCodeEnum.Success;
result.Msg = "操作成功";
result.Data = row;
}
return result;
}
#endregion
}
}
案例如下

5.3.接口
cs
using Frame2_DataModel.MongoEntity.Product;
using Frame6_LibraryUtility;
namespace Frame1_Service.IService.Product
{
/// <summary>
/// MongoDB测试接口
/// </summary>
public interface IProductSvr
{
/// <summary>
/// 获取所有产品
/// </summary>
/// <returns></returns>
Task<ResultModel<List<ProductEntity>>> GetProductAll();
/// <summary>
/// 根据Id获取产品
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
Task<ResultModel<ProductEntity>> GetByIdProduct(string id);
/// <summary>
/// 获取所有产品-分页
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
Task<ResultPageModel<List<ProductEntity>>> GetProductPageList(PageList model);
/// <summary>
/// 保存产品
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
Task<ResultModel<int>> SaveProduct(ProductEntity model);
/// <summary>
/// 根据Id删除产品
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
Task<ResultModel<int>> RemoveProduct(string id);
}
}
案例如下

5.4.控制器
cs
using Frame1_Service.IService.Product;
using Frame2_DataModel.MongoEntity.Product;
using Frame4_LibraryCore.BaseConfig;
using Frame6_LibraryUtility;
using Microsoft.AspNetCore.Mvc;
namespace DemoAPI.Controllers
{
/// <summary>
/// MongoDB测试控制器
/// </summary>
//[Authorize]// 保护整个控制器
[Route("api/[controller]/[action]")]//标记路由地址规格
[ApiController] // 标记该类为 API 控制器,启用一些默认的行为,如模型绑定、输入验证等
[ApiExplorerSettings(GroupName = nameof(ApiVersionInfo.V1))]//设置控制器的API版本
public class ProductController : BaseController
{
/// <summary>
/// 产品
/// </summary>
private readonly IProductSvr _IProductSvr;
/// <summary>
/// 构造
/// </summary>
/// <param name="productSvr"></param>
public ProductController(IProductSvr productSvr)
{
_IProductSvr = productSvr;
}
/// <summary>
/// 获取所有产品
/// </summary>
/// <returns></returns>
[HttpGet]
public async Task<ResultModel<List<ProductEntity>>> GetProductAll() => await _IProductSvr.GetProductAll();
/// <summary>
/// 根据Id获取产品
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpGet]
public async Task<ResultModel<ProductEntity>> GetByIdProduct(string id) => await _IProductSvr.GetByIdProduct(id);
/// <summary>
/// 获取所有产品-分页
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
[HttpPost]
public async Task<ResultPageModel<List<ProductEntity>>> GetProductPageList(PageList model) => await _IProductSvr.GetProductPageList(model);
/// <summary>
/// 保存产品
/// </summary>
/// <param name="model"></param>
/// <returns></returns>
[HttpPost]
public async Task<ResultModel<int>> SaveProduct(ProductEntity model) => await _IProductSvr.SaveProduct(model);
/// <summary>
/// 根据Id删除产品
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
[HttpGet]
public async Task<ResultModel<int>> RemoveProduct(string id) => await _IProductSvr.RemoveProduct(id);
}
}
案例如下
