.NetCore操作MongDB简要代码实现
.NetCore操作MongoDB简要代码实现
MongoDB是用C++编写,基于分布式文件存储的开源的数据库(是nosql类型的数据库)。它旨在为应用提供可扩展的高性能数据库存储解决方案。Mongo将数据以文档的形式存储,它的数据结构是键值对(key-value),其中数据字段存储的不一定是基本类型(int,string,bool...)的数据,它还可以是数组,对象等。
主要概念
DataBase -----数据库,它有自己的集合和权限。不同的数据库是分开文件存放的 Collection -----集合,它是数据库中的文档组,它其实是没有固定结构的!但是在应用中,我们应该是将一类组织结构相同的数据存放在一个集合中。 Document -----文档 ,一条记录就是一个文档,是一组键值对(BSON)。 Field -----字段 ,键值对信息 Index -----索引
MongoDb数据类型
String | 字符串。存储数据常用的数据类型。在 MongoDB 中,UTF-8 编码的字符串才是合法的。 |
Integer | 整型数值。用于存储数值。根据你所采用的服务器,可分为 32 位或 64 位。 |
Boolean | 布尔值。用于存储布尔值(真/假)。 |
Double | 双精度浮点值。用于存储浮点值。 |
Min/Max keys | 将一个值与 BSON(二进制的 JSON)元素的最低值和最高值相对比。 |
Array | 用于将数组或列表或多个值存储为一个键。 |
Timestamp | 时间戳。记录文档修改或添加的具体时间。 |
Object | 用于内嵌文档。 |
Null | 用于创建空值。 |
Symbol | 符号。该数据类型基本上等同于字符串类型,但不同的是,它一般用于采用特殊符号类型的语言。 |
Date | 日期时间。用 UNIX 时间格式来存储当前日期或时间。你可以指定自己的日期时间:创建 Date 对象,传入年月日信息。 |
Object ID | 对象 ID。用于创建文档的 ID。 |
Binary Data | 二进制数据。用于存储二进制数据。 |
Code | 代码类型。用于在文档中存储 JavaScript 代码。 |
Regular expression | 正则表达式类型。用于存储正则表达式。 |
-------------------------------------------------------------------------
以下是.NetCore中简单使用MongoDb
引入如下程序集
MongoDB.Driver
简单封装MongoDB
1、封装获取集合操作
1 public static class MongoCollectionExtension 2 { 3 /// <summary> 4 /// 获取记录数 5 /// </summary> 6 /// <typeparam name="T"></typeparam> 7 /// <param name="collection"></param> 8 /// <param name="expression"></param> 9 /// <returns></returns> 10 public static long GetCount<T>(this IMongoCollection<T> collection, Expression<Func<T, bool>> expression) where T : BaseEntity 11 { 12 return collection.Find(expression).CountDocuments(); 13 } 14 /// <summary> 15 /// 获取记录数 16 /// </summary> 17 /// <typeparam name="T"></typeparam> 18 /// <param name="collection"></param> 19 /// <param name="expression"></param> 20 /// <returns></returns> 21 public static async Task<long> GetCountAsync<T>(this IMongoCollection<T> collection, Expression<Func<T, bool>> expression) where T : BaseEntity 22 { 23 return await collection.Find(expression).CountDocumentsAsync(); 24 } 25 /// <summary> 26 /// 根据Id查询 27 /// </summary> 28 /// <typeparam name="T"></typeparam> 29 /// <param name="collection"></param> 30 /// <param name="id"></param> 31 /// <returns></returns> 32 public static T QueryById<T>(this IMongoCollection<T> collection, string id) where T : BaseEntity 33 { 34 var result = collection.Find(p => p.Id == id).FirstOrDefault(); 35 return result; 36 } 37 /// <summary> 38 /// 根据Id查询 39 /// </summary> 40 /// <typeparam name="T"></typeparam> 41 /// <param name="collection"></param> 42 /// <param name="id"></param> 43 /// <returns></returns> 44 public static async Task<T> QueryByIdAsync<T>(this IMongoCollection<T> collection, string id) where T : BaseEntity 45 { 46 var asyncCursor = await collection.FindAsync(p => p.Id == id); 47 return asyncCursor.FirstOrDefault(); 48 } 49 /// <summary> 50 /// 查询符合条件的第一条记录 51 /// </summary> 52 /// <typeparam name="T"></typeparam> 53 /// <param name="collection"></param> 54 /// <param name="expression"></param> 55 /// <returns></returns> 56 public static T QueryOne<T>(this IMongoCollection<T> collection, Expression<Func<T, bool>> expression) where T : BaseEntity 57 { 58 var result = collection.Find(expression).FirstOrDefault(); 59 return result; 60 } 61 /// <summary> 62 /// 查询符合条件的第一条记录 63 /// </summary> 64 /// <typeparam name="T"></typeparam> 65 /// <param name="collection"></param> 66 /// <param name="expression"></param> 67 /// <returns></returns> 68 public static async Task<T> QueryOneAsync<T>(this IMongoCollection<T> collection, Expression<Func<T, bool>> expression) where T : BaseEntity 69 { 70 var asyncCursor = await collection.FindAsync(expression); 71 return asyncCursor.FirstOrDefault(); 72 } 73 /// <summary> 74 /// 查询符合条件的记录 75 /// </summary> 76 /// <typeparam name="T"></typeparam> 77 /// <param name="collectioin"></param> 78 /// <param name="expression"></param> 79 /// <returns></returns> 80 public static List<T> QueryMany<T>(this IMongoCollection<T> collectioin, Expression<Func<T, bool>> expression,FindOptions findOptions= null) where T : BaseEntity 81 { 82 var result = collectioin.Find(expression, findOptions).ToList(); 83 return result; 84 } 85 /// <summary> 86 /// 查询符合条件的记录 87 /// </summary> 88 /// <typeparam name="T"></typeparam> 89 /// <param name="collection"></param> 90 /// <param name="expression"></param> 91 /// <returns></returns> 92 public static async Task<List<T>> QueryManyAsync<T>(this IMongoCollection<T> collection, Expression<Func<T, bool>> expression, FindOptions<T> findOptions=null) where T : BaseEntity 93 { 94 var asyncCursor = await collection.FindAsync(expression,findOptions); 95 return asyncCursor.ToList(); 96 } 97 98 99 /// <summary> 100 /// 根据指定条件删除 101 /// </summary> 102 /// <typeparam name="T"></typeparam> 103 /// <param name="collection"></param> 104 /// <param name="expression"></param> 105 public static void RemoveMany<T>(this IMongoCollection<T> collection, Expression<Func<T, bool>> expression) where T : BaseEntity 106 { 107 collection.DeleteMany(expression); 108 } 109 /// <summary> 110 /// 根据指定条件删除 111 /// </summary> 112 /// <typeparam name="T"></typeparam> 113 /// <param name="collection"></param> 114 /// <param name="expression"></param> 115 /// <returns></returns> 116 public static async Task RemoveManyAsync<T>(this IMongoCollection<T> collection, Expression<Func<T, bool>> expression) where T : BaseEntity 117 { 118 await collection.DeleteManyAsync(expression); 119 } 120 /// <summary> 121 /// 根据id移除 122 /// </summary> 123 /// <typeparam name="T"></typeparam> 124 /// <param name="collection"></param> 125 /// <param name="id"></param> 126 public static void RemoveById<T>(this IMongoCollection<T> collection, string id) where T : BaseEntity 127 { 128 collection.DeleteOne(p => p.Id == id); 129 } 130 /// <summary> 131 /// 根据id移除 132 /// </summary> 133 /// <typeparam name="T"></typeparam> 134 /// <param name="collection"></param> 135 /// <param name="id"></param> 136 /// <returns></returns> 137 public static async Task RemoveByIdAsync<T>(this IMongoCollection<T> collection, string id) where T : BaseEntity 138 { 139 await collection.DeleteOneAsync(p => p.Id == id); 140 } 141 /// <summary> 142 /// 移除指定记录 143 /// </summary> 144 /// <typeparam name="T"></typeparam> 145 /// <param name="collection"></param> 146 /// <param name="t"></param> 147 public static void RemoveOne<T>(this IMongoCollection<T> collection, T t) where T : BaseEntity 148 { 149 collection.DeleteOne(p => p.Id == t.Id); 150 } 151 /// <summary> 152 /// 移除指定记录 153 /// </summary> 154 /// <typeparam name="T"></typeparam> 155 /// <param name="collection"></param> 156 /// <param name="t"></param> 157 /// <returns></returns> 158 public static async Task RemoveOneAsync<T>(this IMongoCollection<T> collection, T t) where T : BaseEntity 159 { 160 await collection.DeleteOneAsync(p => p.Id == t.Id); 161 } 162 /// <summary> 163 /// 新增 164 /// </summary> 165 /// <typeparam name="T"></typeparam> 166 /// <param name="collection"></param> 167 /// <param name="t"></param> 168 /// <param name="userId"></param> 169 public static void AddOne<T>(this IMongoCollection<T> collection, T t, string userId) where T : BaseEntity 170 { 171 CompleteCreatedEntity(t, userId); 172 collection.InsertOne(t); 173 } 174 /// <summary> 175 /// 新增 176 /// </summary> 177 /// <typeparam name="T"></typeparam> 178 /// <param name="collection"></param> 179 /// <param name="t"></param> 180 /// <param name="userId"></param> 181 /// <returns></returns> 182 public static async Task AddOneAsync<T>(this IMongoCollection<T> collection, T t, string userId) where T : BaseEntity 183 { 184 CompleteCreatedEntity(t, userId); 185 await collection.InsertOneAsync(t); 186 } 187 /// <summary> 188 /// 新增多个 189 /// </summary> 190 /// <typeparam name="T"></typeparam> 191 /// <param name="collection"></param> 192 /// <param name="list"></param> 193 /// <param name="userId"></param> 194 public static void AddMany<T>(this IMongoCollection<T> collection, List<T> list, string userId) where T : BaseEntity 195 { 196 list.ForEach(p => CompleteCreatedEntity(p, userId)); 197 collection.InsertMany(list); 198 } 199 /// <summary> 200 /// 新增多个 201 /// </summary> 202 /// <typeparam name="T"></typeparam> 203 /// <param name="collection"></param> 204 /// <param name="list"></param> 205 /// <param name="userId"></param> 206 /// <returns></returns> 207 public static async Task AddManyAsync<T>(this IMongoCollection<T> collection, List<T> list, string userId = "") where T : BaseEntity 208 { 209 list.ForEach(p => CompleteCreatedEntity(p, userId)); 210 await collection.InsertManyAsync(list); 211 } 212 /// <summary> 213 /// 根据Id更新 214 /// </summary> 215 /// <typeparam name="T"></typeparam> 216 /// <param name="collection"></param> 217 /// <param name="updateDefinition"></param> 218 /// <param name="id"></param> 219 /// <param name="userId"></param> 220 public static void UpdateOneById<T>(this IMongoCollection<T> collection, UpdateDefinition<T> updateDefinition, string id, string userId = "") where T : BaseEntity 221 { 222 updateDefinition = updateDefinition.Set(p => p.LastModifiedUtc, DateTime.UtcNow) 223 .Set(p => p.LastModifierId, userId); 224 collection.UpdateOne(p => p.Id == id, updateDefinition); 225 } 226 /// <summary> 227 /// 根据Id更新 228 /// </summary> 229 /// <typeparam name="T"></typeparam> 230 /// <param name="collection"></param> 231 /// <param name="updateDefinition"></param> 232 /// <param name="id"></param> 233 /// <param name="userId"></param> 234 /// <returns></returns> 235 public static async Task UpdateOneByIdAsync<T>(this IMongoCollection<T> collection, UpdateDefinition<T> updateDefinition, string id, string userId = "") where T : BaseEntity 236 { 237 updateDefinition = updateDefinition.Set(p => p.LastModifiedUtc, DateTime.UtcNow) 238 .Set(p => p.LastModifierId, userId); 239 await collection.UpdateOneAsync(p => p.Id == id, updateDefinition); 240 } 241 242 /// <summary> 243 /// 更新 244 /// </summary> 245 /// <typeparam name="T"></typeparam> 246 /// <param name="collection"></param> 247 /// <param name="t"></param> 248 /// <param name="userId"></param> 249 public static void UpdateEntity<T>(this IMongoCollection<T> collection, T t, string userId) where T : BaseEntity 250 { 251 t.LastModifierId = userId; 252 t.LastModifiedUtc = DateTime.UtcNow; 253 collection.ReplaceOne(p => p.Id == t.Id,t); 254 } 255 /// <summary> 256 /// 更新 257 /// </summary> 258 /// <typeparam name="T"></typeparam> 259 /// <param name="collection"></param> 260 /// <param name="t"></param> 261 /// <param name="userId"></param> 262 public static async Task UpdateEntityAsync<T>(this IMongoCollection<T> collection, T t, string userId) where T : BaseEntity 263 { 264 t.LastModifierId = userId; 265 t.LastModifiedUtc = DateTime.UtcNow; 266 var result = await collection.ReplaceOneAsync(p=>p.Id==t.Id,t); 267 } 268 /// <summary> 269 /// 根据条件更新多个 270 /// </summary> 271 /// <typeparam name="T"></typeparam> 272 /// <param name="collectioin"></param> 273 /// <param name="updateDefinition"></param> 274 /// <param name="expresion"></param> 275 /// <param name="userId"></param> 276 public static void UpdateMultiple<T>(this IMongoCollection<T> collectioin, UpdateDefinition<T> updateDefinition, Expression<Func<T, bool>> expresion, string userId = "") where T : BaseEntity 277 { 278 updateDefinition = updateDefinition.Set(p => p.LastModifiedUtc, DateTime.UtcNow) 279 .Set(p => p.LastModifierId, userId); 280 collectioin.UpdateMany(expresion, updateDefinition); 281 } 282 /// <summary> 283 /// 根据条件更新多个 284 /// </summary> 285 /// <typeparam name="T"></typeparam> 286 /// <param name="collectioin"></param> 287 /// <param name="updateDefinition"></param> 288 /// <param name="expresion"></param> 289 /// <param name="userId"></param> 290 /// <returns></returns> 291 public static async Task UpdateMultipleAsync<T>(this IMongoCollection<T> collectioin, UpdateDefinition<T> updateDefinition, Expression<Func<T, bool>> expresion, string userId = "") where T : BaseEntity 292 { 293 updateDefinition = updateDefinition.Set(p => p.LastModifiedUtc, DateTime.UtcNow) 294 .Set(p => p.LastModifierId, userId); 295 await collectioin.UpdateManyAsync(expresion, updateDefinition); 296 } 297 /// <summary> 298 /// 补全新增的数据信息 299 /// </summary> 300 /// <typeparam name="T"></typeparam> 301 /// <param name="t"></param> 302 public static void CompleteCreatedEntity<T>(T t, string userId) where T : BaseEntity 303 { 304 DateTime utcNow = DateTime.UtcNow; 305 t.CreatedUtcTime = utcNow; 306 t.LastModifiedUtc = utcNow; 307 t.CreatorId = userId; 308 t.LastModifierId = userId; 309 } 310 }
配置、实体类信息
MongoDbSetting:配置mongodb连接信息
1 /// <summary> 2 /// mongodb setting 3 /// </summary> 4 public class MongoDbSetting 5 { 6 /// <summary> 7 /// connection string 8 ///for example mongodb://host1:27017,host2:27017 9 /// </summary> 10 public string Connection { get; set; } 11 /// <summary> 12 /// database name 13 /// </summary> 14 public string Database { get; set; } 15 }
配置信息示例
1 "MongoDbSetting": { 2 "Connection": "mongodb://localhost:27017", 3 "Database": "ProductDb" 4 }
BaseEntity是数据库实体的基类,用于声明一些共用的字段,以及限定数据库实体类型。
BaseEntity定义
1 /// <summary> 2 /// base entity 3 /// </summary> 4 public class BaseEntity 5 { 6 /// <summary> 7 /// id 8 /// </summary> 9 [BsonId] 10 [BsonRepresentation(BsonType.ObjectId)] 11 public string Id { get; set; } 12 public string CreatorId { get; set; } 13 public DateTime CreatedUtcTime { get; set; } 14 public string LastModifierId { get; set; } 15 public DateTime LastModifiedUtc { get; set; } 16 }
Product.cs
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 public class Product : BaseEntity 2 { 3 public string SKU { get; set; } 4 public string Title { get; set; } 5 public string ShortDescription { get; set; } 6 public string Description { get; set; } 7 public string DisplayName { get; set; } 8 public string CategoryId { get; set; } 9 public List<string> Brands { get; set; } 10 public double Price { get; set; } 11 public int Qty { get; set; } 12 public Dictionary<string, object> Attributes { get; set; } 13 14 }
简单测试使用
以下是简单的service层调用,关于NetCore中对mongodb context进行注入,此处略
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 public class ProductService : IProductService 2 { 3 private readonly MongoDbContext _context; 4 public ProductService(MongoDbContext context) 5 { 6 this._context = context; 7 } 8 public async Task AddProductAsync(Product newProduct) 9 { 10 await _context.GetCollection<Product>().AddOneAsync(newProduct,"100001"); 11 } 12 13 public async Task DeleteProductByIdAsync(string id) 14 { 15 await _context.GetCollection<Product>().RemoveByIdAsync(id); 16 } 17 18 public async Task<Product> GetProductByIdAsync(string id) 19 { 20 return await _context.GetCollection<Product>().QueryByIdAsync(id); 21 } 22 23 public async Task<List<Product>> GetProductByCategoryIdAsync(string categoryId,int pageIndex,int pageSize) 24 { 25 Expression<Func<Product, bool>> expression = p => p.CategoryId == categoryId; 26 FindOptions<Product> findOptions = new FindOptions<Product>(); 27 //分页 28 int skipCount = (pageIndex - 1) * pageSize; 29 findOptions.Skip = skipCount; 30 findOptions.Limit = pageSize; 31 //排序 32 var sort = Builders<Product>.Sort.Ascending(p=>p.CreatedUtcTime).Ascending(p=>p.LastModifiedUtcTime); 33 findOptions.Sort = sort; 34 return await _context.GetCollection<Product>().QueryManyAsync(expression); 35 36 } 37 38 public async Task UpdateProductAsync(Product product) 39 { 40 await _context.GetCollection<Product>().UpdateEntityAsync(product,"admin"); 41 } 42 43 }
----------------附------------------
1、对IMongoCollection进行扩展,定义符合业务的数据通用操作,当然也可以根据实际情况直接使用mongodb的net driver的原生接口操作。本文是自定义的业务规范,在调用时一般都是调用封装进行操作的。但是对于子集(内部对象(特别时一些动态数据时,例如Dictionary))的查询时,可以直接使用Builders<>.Filter指定字段进行查询。示例
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 public async Task GetProduct(ProductSearchContract contract) 2 { 3 var filterBuilder = Builders<Product>.Filter; 4 var filter = filterBuilder.Empty; 5 if (!string.IsNullOrEmpty(contract.SKU)) 6 { 7 filter &= filterBuilder.Eq(p => p.SKU, contract.SKU); 8 } 9 if (!string.IsNullOrEmpty(contract.Model)) 10 { 11 filter &= filterBuilder.Eq("Attributes.Model", contract.Model); // 12 } 13 if (contract.ListingTimeFrom != null && contract.ListingTimeFrom.Value > DateTime.MinValue) 14 { 15 filter &= filterBuilder.Lte("Attributes.ListingTime", contract.ListingTimeFrom.Value.Date.ToString("yyyy-MM-dd")); // 16 } 17 18 await _context.GetCollection<Product>().FindAsync(filter); 19 }
2、在mongodb中Id(主键)的数据类型是ObjectId。但是在本文BaseEntity的定义中,Id使用的string类型。是因为ObjectId是mongodb定义的数据类型,它不是C#的通用类型,如果在程序中使用objectId,会导致数据类型转换或者不必要的引用。在声明时使用[BsonId][BsonRepresentation(BsonType.ObjectId)]特性。
3、在调用mongodb原生接口中,可以发现MongoDB没有对数据库连接进行open和close操作。其实mongodb driver推荐使用单例的mongodb连接,它是线程安全。
4、关于mongodb的事务,在单机作为服务器的情况是不需要的(单机服务器使用mongodb事务会报错【Standalone servers do not support transactions】),只有在集群情况下才会有用。本文暂不考虑构建仓储,使用工作单元的方式(感觉mongodb没有必要做成仓储的方式,仓储-工作单元方式更多的是为关系型数据库实现事务的)。参阅mongodb的事务。
5、mongdb driver操作collection,在进行数据插入时发现没有此collection则会自动创建(无需指定创建)。当collection不存在时进行查询是不会报错的,查询结果为空!
6、MongoDB是文档型数据库,对于大量数据的操作存储方面的性能较之关系型数据库优势还是比较明显的。在应用系统中日志数据(错误日志,操作日志等)还是比较庞大的,特别是随着系统运行。日志信息存放在关系型数据库中占用空间大,而且也不利于检索。所以在不少公司中用MongoDb存储系统日志信息。当然利用MongoDb存储实际业务数据的也不少的。
-------- 参考文档 ----------
https://mongodb.github.io/mongo-csharp-driver/
https://www.runoob.com/mongodb/mongodb-tutorial.html