使用mongoDB c#驱动程序仅按日期过滤

Gha*_*han 9 c# mongodb mongodb-.net-driver

我在我的项目中使用mongoDB c#最新驱动程序,即3. +.我使用daterangepicker有不同的日期过滤条件,如今天,最后一天,昨天,本月等.

这是我的模特

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; }
    }
Run Code Online (Sandbox Code Playgroud)

这是驱动程序代码

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();
Run Code Online (Sandbox Code Playgroud)

这段代码工作正常但是当我选择今天的过滤器时,日期就变成了

var start = new DateTime(2017, 03, 31);
var end = new DateTime(2017, 03, 31);
Run Code Online (Sandbox Code Playgroud)

它没有返回当天的记录.它也在计算时间.

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

"CreatedOn": ISODate("2017-03-31T20:27:12.914+05:00"),
"ModifiedOn": ISODate("2017-03-31T20:27:12.914+05:00"),
Run Code Online (Sandbox Code Playgroud)

这是我正在使用的日期过滤器.我应该从结束日期减去-1吗? 在此输入图像描述

需要帮助我做错了什么.

use*_*814 8

我相信你对时区特别是偏移部分感到困惑.

MongoDb始终以UTC时间保存日期.

因此,当您查看MongoDB中的日期时间时,您必须考虑与当地时区的偏移量.

您将始终以当地时区发送日期.Mongo C#驱动程序在持久化之前将时间从本地更改为UTC.

例如

当我使用CreatedOn = 2017-04-05 15:21:23.234(本地时区(美国/芝加哥))保存文档时,但是当您查看数据库中的文档时,您将看到一些内容,ISODate("2017-04-05T20:21:23.234Z")即UTC的本地时间偏移,即-5小时.

[BsonDateTimeOptions(Kind = DateTimeKind.Local)] 表示驱动程序在将BSON退回到您的POCO时将时间从UTC转换为本地时间.

这是解释行为的测试用例.

代码:

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; }
}
Run Code Online (Sandbox Code Playgroud)

收藏:(通过mongo shell查看)

{
        "_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"
}
Run Code Online (Sandbox Code Playgroud)

更新:

"CreatedOn": ISODate("2017-03-31T20:27:12.914+05:00")
Run Code Online (Sandbox Code Playgroud)

你的比较不起作用的原因是

 var start = new DateTime(2017, 03, 31);
 var end = new DateTime(2017, 03, 31);
Run Code Online (Sandbox Code Playgroud)

这被发送到服务器作为$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);
Run Code Online (Sandbox Code Playgroud)

并将您的过滤器更新为

var filter = filterBuilder.Gte(x => x.CreatedOn, start) &
         filterBuilder.Lt(x => x.CreatedOn, end);
Run Code Online (Sandbox Code Playgroud)

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

更新2

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

更改要使用的保存方法

var today = DateTime.Today; //2017-03-31 00:00:00.000
Run Code Online (Sandbox Code Playgroud)

您可以返回旧的过滤器定义.

就像是

 var start = new DateTime(2017, 03, 31);
 var end = new DateTime(2017, 03, 31);
Run Code Online (Sandbox Code Playgroud)

并将您的过滤器更新为

var filter = filterBuilder.Gte(x => x.CreatedOn, start) &
         filterBuilder.Lte(x => x.CreatedOn, end);
Run Code Online (Sandbox Code Playgroud)

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

更新3 - 仅使用日期比较BsonDocument.

这里的想法是添加时区偏移量,该时区偏移量是+5:00服务器的UTC日期,并yyyy-MM-dd使用$dateToSting运算符将计算的日期时间转换为字符串格式,然后以相同格式比较输入字符串日期.

这将在您的时区中起作用,但在DST观察时区中不起作用.

Mongo版本3.4

您可以使用$addFields添加新字段的阶段,CreatedOnDate同时保留所有现有属性,并在比较后最后从最终响应中$project删除CreatedOnDate.

Shell查询:

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

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();
Run Code Online (Sandbox Code Playgroud)

Mongo版本= 3.2

与上面相同,但是此管道使用,$project因此您必须添加要在最终响应中保留的所有字段.

Shell查询:

{
    "$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
    }
}
Run Code Online (Sandbox Code Playgroud)

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();
Run Code Online (Sandbox Code Playgroud)

更新4 - 仅与日期相关的日期比较.

Mongo版本= 3.6

一切都保持不变,期望$dateToString将采用时区而不是固定的偏移量,这应该考虑到日间的灯光节省变化.

壳牌更新:

{
    "$addFields": {
        "CreatedOnDate": {
            "$dateToString": {
                "format": "%Y-%m-%d",
                "date": "$CreatedOn",
                "timezone": "America/New_York"
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

C#更新:

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