2017-04-02 70 views
7

我使用MongoDB的C#最新的驱动程序即3 +在我的项目。我有不同的日期过滤标准像今天最后一天,昨天,本月等使用daterangepicker。过滤器只能通过使用日期MongoDB的C#驱动

这里是我的模型

public class Student 
    { 
     public Student() 
     { 
     } 
     [BsonId] 
     [BsonRepresentation(BsonType.ObjectId)] 
     public string Id { get; set; } 
     [BsonDateTimeOptions(Kind = DateTimeKind.Local)] 
     public DateTime CreatedOn { get; set; } 
     [BsonDateTimeOptions(Kind = DateTimeKind.Local)] 
     public DateTime ModifiedOn { get; set; } 
     public string Name { get; set; } 
     public string Description { get; set; } 
    } 

这里是驱动程序代码

var server = new MongoClient(_connectionString); 
var db = server.GetDatabase("Students"); 
var collection = db.GetCollection<Student>("student"); 
var filterBuilder = Builders<Student>.Filter; 
var start = new DateTime(2017, 03, 29); 
var end = new DateTime(2017, 03, 31); 
var filter = filterBuilder.Gte(x => x.CreatedOn, new BsonDateTime(start)) & 
      filterBuilder.Lte(x => x.CreatedOn, new BsonDateTime(end)); 
List<Student> searchResult = collection.Find(filter).ToList(); 

此代码工作正常,但是当我选择今天的筛选,然后日期变成

var start = new DateTime(2017, 03, 31); 
var end = new DateTime(2017, 03, 31); 

它没不会返回当天的记录。它也是计算时间。

我将日期保存为DateTime.Now。我正在查询的样本ISO日期是

"CreatedOn": ISODate("2017-03-31T20:27:12.914+05:00"), 
"ModifiedOn": ISODate("2017-03-31T20:27:12.914+05:00"), 

这是我正在使用的日期过滤器。我应该有subract -1的结束日期? enter image description here

需要帮助我做错了什么。

+0

你能从你的收藏,你期待你的当前日期查询返回添加样本文档? – Veeram

+0

我在数据库中保存了DateTime.Now,看到我编辑的问题 –

+0

Thanls @Veeram今天的例子我可以使用AddDays方法,但其他方法呢,我已经更新了我有的日期的过滤器。需要某种通用解决方案。 –

回答

-1

当您使用

new DateTime(2017, 03, 31); 

你得到一个DateTime对象,这意味着它计算时间也。 因此,通过使用相同的解析为两个启动和停止,你真正得到的东西等于:

var start = var end = new DateTime("31/03/2017 00:00:00.00"); 

当然,你可能有这个具体的时间框架下没有记录。 如果你真的想要得到今天的一切记录,你应该做这样的事情:

var start = new DateTime("31/03/2017 00:00:00.00"); 
var end = new DateTime("31/03/2017 23:59:59.99"); 
+0

没有重载拿字符串参数.. –

+0

@GhazanfarKhan他在这里帮助你。如果他错了,就让他知道。不需要使用这样的语言。希望你能理解。 – Sachin

+0

明白了,但我并不期待这一点。 –

2

我相信你正在使用的时区混淆特别是抵消一部分。

MongoDb总是以UTC时间保存日期。

所以,当你在MongoDB中查看日期时间时,你总是必须将偏离当地时区的因子考虑在内。

您将始终在当地时区发送日期。蒙戈C#驱动程序之前,坚持从本地更改时间UTC。

例如

当我保存CreatedOn = 2017-04-05 15:21:23.234(当地时区(美国/芝加哥)),但 文档当你看到在DB你会看到一些ISODate("2017-04-05T20:21:23.234Z")即本地时间与UTC这是抵消的文件-5个小时。

[BsonDateTimeOptions(Kind = DateTimeKind.Local)]指示驱动程序将时间从UTC转换为当地时间,然后将BSON返回到您的POCO。

下面是测试情况解释的行为。

代码:

class Program 
{ 

    static void Main(string[] args) 
    { 
     var mongo = new MongoClient("mongodb://localhost:27017/test"); 
     var db = mongo.GetDatabase("test"); 

     db.DropCollection("students"); 
     db.CreateCollection("students"); 

     var collection = db.GetCollection<Student>("students"); 

     var today = DateTime.Now; //2017-04-05 15:21:23.234 
     var yesterday = today.AddDays(-1);//2017-04-04 15:21:23.234 

     // Create 2 documents (yesterday & today) 
     collection.InsertMany(new[] 
      { 
      new Student{Description = "today", CreatedOn = today}, 
      new Student{Description = "yesterday", CreatedOn = yesterday}, 
      } 
     ); 

     var filterBuilder1 = Builders<Student>.Filter; 
     var filter1 = filterBuilder1.Eq(x => x.CreatedOn, today); 
     List<Student> searchResult1 = collection.Find(filter1).ToList(); 

     Console.Write(searchResult1.Count == 1); 

     var filterBuilder2 = Builders<Student>.Filter; 
     var filter2 = filterBuilder2.Eq(x => x.CreatedOn, yesterday); 
     List<Student> searchResult2 = collection.Find(filter2).ToList(); 

     Console.Write(searchResult2.Count == 1); 

    } 
} 

public class Student 
{ 
    [BsonId] 
    [BsonRepresentation(BsonType.ObjectId)] 
    public string Id { get; set; } 
    [BsonDateTimeOptions(Kind = DateTimeKind.Local)] 
    public DateTime CreatedOn { get; set; } 
    public string Description { get; set; } 
} 

收集:(通过蒙戈壳观察时)

{ 
     "_id" : ObjectId("58e559c76d3a9d2cb0449d84"), 
     "CreatedOn" : ISODate("2017-04-04T20:21:23.234Z"), 
     "Description" : "yesterday" 
} 
{ 
     "_id" : ObjectId("58e559c76d3a9d2cb0449d85"), 
     "CreatedOn" : ISODate("2017-04-05T20:21:23.234Z"), 
     "Description" : "today" 
} 

更新:

"CreatedOn": ISODate("2017-03-31T20:27:12.914+05:00") 

你的比较是不工作的原因是

var start = new DateTime(2017, 03, 31); 
var end = new DateTime(2017, 03, 31); 

这得到发送到服务器作为$gteISODate("2017-03-31T00:00:00.000+05:00")$lteISODate("2017-03-31T00:00:00.000+05:00")和它不发现上面的条目。

正确的方法来查询today日期将是

var start = new DateTime(2017, 03, 31); 
var end = new DateTime(2017, 04, 01); 

和更新您的过滤器

var filter = filterBuilder.Gte(x => x.CreatedOn, start) & 
     filterBuilder.Lt(x => x.CreatedOn, end); 

所以,现在你的范围查询发送到服务器$gteISODate("2017-03-31T00:00:00.000+05:00")$ltISODate("2017-04-01T00:00:00.000+05:00")你应该能够找到今天的所有比赛。

更新2

更改数据库的日期与时间部分时间设定存储为00:00:00。这将从db中删除等式中的时间部分,并且您的旧范围查询将适用于所有情况。

更改保存方法使用

​​

你可以回到旧的过滤器定义。

喜欢的东西

var start = new DateTime(2017, 03, 31); 
var end = new DateTime(2017, 03, 31); 

和更新您的过滤器

var filter = filterBuilder.Gte(x => x.CreatedOn, start) & 
     filterBuilder.Lte(x => x.CreatedOn, end); 

所以,现在你的范围查询发送到服务器$gteISODate("2017-03-31T00:00:00.000+05:00")$lteISODate("2017-03-31T00:00:00.000+05:00"),你应该能够找到所有今天比赛。

更新3 - 仅限日期使用BsonDocument进行比较。

这里的想法是添加区偏移量是+5:00服务器的UTC日期和变换计算的日期时间使用$dateToSting运营商随后在相同格式的输入字符串日期比较字符串yyyy-MM-dd格式。

这会在你的时区工作,但不会DST工作观测时区。

蒙戈3.4版本

您可以使用$addFields阶段它增加了新的领域CreatedOnDate同时保持所有现有的属性和最后$project从最终反应比较后丢弃CreatedOnDate

壳牌查询:

{ 
    "$addFields": { 
     "CreatedOnDate": { 
      "$dateToString": { 
       "format": "%Y-%m-%d", 
       "date": { 
        "$add": ["$CreatedOn", 18000000] 
       } 
      } 
     } 
    } 
}, { 
    "$match": { 
     "CreatedOnDate": { 
      "$gte": "2017-03-31", 
      "$lte": "2017-03-31" 
     } 
    } 
}, { 
    "$project": { 
     "CreatedOnDate": 0 
    } 
} 

C#代码:

var start = new DateTime(2017, 03, 31); 
var end = new DateTime(2017, 03, 31); 

var addFields = BsonDocument.Parse("{$addFields: { CreatedOnDate: { $dateToString: { format: '%Y-%m-%d', date: {$add: ['$CreatedOn', 18000000] }} }} }"); 

var match = new BsonDocument("CreatedOnDate", new BsonDocument("$gte", start.ToString("yyyy-MM-dd")).Add("$lte", end.ToString("yyyy-MM-dd"))); 

var project = new BsonDocument 
    { 
     { "CreatedOnDate", 0 } 
    }; 

var pipeline = collection.Aggregate().AppendStage<BsonDocument>(addFields) 
    .Match(match) 
    .Project(project); 

var list = pipeline.ToList(); 

List<Student> searchResult = list.Select(doc => BsonSerializer.Deserialize<Student>(doc)).ToList(); 

蒙戈版= 3.2

同上,但这个管道使用$project所以你必须添加所有您希望保留在最终响应中的字段。

壳牌查询:

{ 
    "$project": { 
     "CreatedOn": 1, 
     "Description": 1, 
     "CreatedOnDate": { 
      "$dateToString": { 
       "format": "%Y-%m-%d", 
       "date": { 
        "$add": ["$CreatedOn", 18000000] 
       } 
      } 
     } 
    } 
}, { 
    "$match": { 
     "CreatedOnDate": { 
      "$gte": "2017-03-31", 
      "$lte": "2017-03-31" 
     } 
    } 
}, { 
    "$project": { 
     "CreatedOn": 1, 
     "Description": 1 
    } 
} 

C#代码:

var start = new DateTime(2017, 03, 31); 
var end = new DateTime(2017, 03, 31); 

var project1 = new BsonDocument 
    { 
     { "CreatedOn", 1 }, 
     { "Description", 1 }, 
     { "CreatedOnDate", new BsonDocument("$dateToString", new BsonDocument("format", "%Y-%m-%d") 
          .Add("date", new BsonDocument("$add", new BsonArray(new object[] { "$CreatedOn", 5 * 60 * 60 * 1000 })))) 
     } 
    }; 

var match = new BsonDocument("CreatedOnDate", new BsonDocument("$gte", start.ToString("yyyy-MM-dd")).Add("$lte", end.ToString("yyyy-MM-dd"))); 

var project2 = new BsonDocument 
    { 
     { "CreatedOn", 1 }, 
     { "Description", 1 } 
    }; 


var pipeline = collection.Aggregate() 
.Project(project1) 
.Match(match) 
.Project(project2); 

var list = pipeline.ToList(); 

List<Student> searchResult = list.Select(doc => BsonSerializer.Deserialize<Student>(doc)).ToList(); 

更新4 - 有储蓄天灯工作日期只有比较。

蒙戈版= 3.6

一切都保持相同的期望$dateToString将采取时区,而不是固定偏移量应该照顾日光节约变化考虑进去。

壳牌更新:

{ 
    "$addFields": { 
     "CreatedOnDate": { 
      "$dateToString": { 
       "format": "%Y-%m-%d", 
       "date": "$CreatedOn", 
       "timezone": "America/New_York" 
      } 
     } 
    } 
} 

C#更新:

var addFields = BsonDocument.Parse("{$addFields: { CreatedOnDate: { $dateToString: { format: '%Y-%m-%d', date: "$CreatedOn", "timezone": "America/New_York"} }} }"); 
+0

我想存储时间部分也如何使用您的答案,您不使用DateTime.Now –

+0

添加时间部分的例子。从比较查询的答案的“更新”部分使用'filterDefinition'。 – Veeram

+0

如果我不得不在服务器端过滤日期而不是使用daterangepicker的日期。我可以在客户端做到吗? –