MongoDB按日期过滤集合时DateTime.ParseExact不支持异常排查
问题:MongoDB按日期过滤集合时出现不支持ParseExact的错误
场景与代码
尝试对MongoDB的HotelBookingCollection集合按日期范围过滤,相关代码如下:
HotelBookingDocument.cs
public string CreationDate { get; set; } // 其余代码省略
集合定义
public IMongoCollection<HotelBookingDocument> HotelBookingCollection { get; set; }
查询逻辑(输入参数为string类型的Start和End)
DateTime startDate; DateTime endDate; var query = new List<HotelBookingDocument>(); if (!string.IsNullOrEmpty(Start) && !string.IsNullOrEmpty(End)) { startDate = DateTime.ParseExact(Start + " " + "00:00:00", "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); // 此处执行正常 endDate = DateTime.ParseExact(End + " " + "00:00:00", "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); // 此处执行正常 query = await HotelBookingCollection.Find(s => ( startDate <= DateTime.ParseExact(s.CreationDate + " " + "00:00:00", "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture) && DateTime.ParseExact(s.CreationDate + " " + "00:00:00", "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture) <= endDate) ).ToListAsync(); } // 错误发生在此行
错误信息
System.InvalidOperationException: ParseExact((({document}{CreationDate} + " ") + "00:00:00"), "yyyy-MM-dd HH:mm:ss", ) is not supported. at MongoDB.Driver.Linq.Linq2Implementation.Translators.PredicateTranslator.GetFieldExpression(Expression expression) at MongoDB.Driver.Linq.Linq2Implementation.Translators.PredicateTranslator.TranslateComparison(Expression variableExpression, ExpressionType operatorType, ConstantExpression constantExpression) at MongoDB.Driver.Linq.Linq2Implementation.Translators.PredicateTranslator.TranslateComparison(BinaryExpression binaryExpression) at MongoDB.Driver.Linq.Linq2Implementation.Translators.PredicateTranslator.Translate(Expression node) at MongoDB.Driver.Linq.Linq2Implementation.Translators.PredicateTranslator.TranslateAndAlso(BinaryExpression node) at MongoDB.Driver.Linq.Linq2Implementation.Translators.PredicateTranslator.Translate(Expression node) at MongoDB.Driver.Linq.Linq2Implementation.Translators.PredicateTranslator.Translate(Expression node, IBsonSerializerRegistry serializerRegistry) at MongoDB.Driver.Linq.Linq2Implementation.Translators.QueryableTranslator.TranslateWhere(WhereExpression node) at MongoDB.Driver.Linq.Linq2Implementation.Translators.QueryableTranslator.Translate(Expression node) at MongoDB.Driver.Linq.Linq2Implementation.Translators.QueryableTranslator.TranslatePipeline(PipelineExpression node) at MongoDB.Driver.Linq.Linq2Implementation.Translators.QueryableTranslator.Translate(Expression node) at MongoDB.Driver.Linq.Linq2Implementation.Translators.QueryableTranslator.Translate(Expression node, IBsonSerializerRegistry serializerRegistry, ExpressionTranslationOptions translationOptions) at MongoDB.Driver.Linq.Linq2Implementation.MongoQueryProviderImpl`1.Translate(Expression expression) at MongoDB.Driver.Linq.Linq2Implementation.MongoQueryProviderImpl`1.Execute(Expression expression) at MongoDB.Driver.Linq.Linq2Implementation.MongoQueryableImpl`2.GetEnumerator() at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection) at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
原因与解决方案
问题原因
MongoDB LINQ驱动无法将.NET中的DateTime.ParseExact方法转换为MongoDB可识别的查询语句,该方法没有对应的MongoDB查询操作符。
解决方案
有两种可行解决方式:
方案1:修改实体类字段类型(推荐)
将CreationDate的类型从string改为DateTime,MongoDB会自动存储为日期类型,查询时直接比较日期即可:
// 修改HotelBookingDocument.cs public DateTime CreationDate { get; set; }
查询逻辑简化为:
if (!string.IsNullOrEmpty(Start) && !string.IsNullOrEmpty(End)) { startDate = DateTime.ParseExact(Start + " 00:00:00", "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); endDate = DateTime.ParseExact(End + " 23:59:59", "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); // 改为当天结束时间,避免漏查数据 query = await HotelBookingCollection.Find(s => s.CreationDate >= startDate && s.CreationDate <= endDate) .ToListAsync(); }
方案2:使用MongoDB日期转换操作(不推荐,性能较差)
若无法修改实体类,可使用MongoDB的$dateFromString操作符构建聚合查询,将字符串转换为日期后再比较:
if (!string.IsNullOrEmpty(Start) && !string.IsNullOrEmpty(End)) { startDate = DateTime.ParseExact(Start + " 00:00:00", "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); endDate = DateTime.ParseExact(End + " 23:59:59", "yyyy-MM-dd HH:mm:ss", CultureInfo.InvariantCulture); var pipeline = new BsonDocument[] { new BsonDocument("$addFields", new BsonDocument( "creationDateObj", new BsonDocument("$dateFromString", new BsonDocument { { "dateString", new BsonDocument("$concat", new BsonArray { "$CreationDate", " 00:00:00" }) }, { "format", "yyyy-MM-dd HH:mm:ss" } }) )), new BsonDocument("$match", new BsonDocument { "creationDateObj", new BsonDocument { { "$gte", startDate }, { "$lte", endDate } } }) }; query = await HotelBookingCollection.Aggregate<HotelBookingDocument>(pipeline).ToListAsync(); }
注意事项
- 方案1为最优解,MongoDB对日期类型的查询支持更完善,还可创建索引提升查询性能。
- 方案2需在查询时动态转换字段,无法利用索引,数据量大时性能会显著下降。
内容的提问来源于stack exchange,提问作者hanushi-thana
相关产品推荐
相关产品推荐

