Properly using / handling DateTimeOffset in MongoDB

筅森魡賤 提交于 2021-02-04 14:48:05

问题


public class ScheduledEvent : Event
{
    public DateTimeOffset StartDateTime { get; set; }
}

StartDateTime = 5/27/2013 2:09:00 AM +00:00 representing 05/26/2013 07:09 PM PST

What's recorded in MongoDB:

> db.ScheduledEvent.find().toArray()
[
        {
                "_id" : BinData(3,"ZE2p31dh00qb6kglsgHgAA=="),
                "Title" : "Today 26th at 7:09pm",
                "Length" : "00:00:00",
                "MoreInformation" : "http://1.com",
                "Speakers" : [
                        {
                                "_id" : BinData(3,"ndzESsQGukmYGmMgKK0EqQ=="),
                                "Name" : "Mathias Brandewinder"
                        }
                ],
                "Location" : {
                        "_id" : BinData(3,"AAAAAAAAAAAAAAAAAAAAAA=="),
                        "Name" : "Somwhere "
                },
                "Organizers" : [
                        {
                                "_id" : BinData(3,"AAAAAAAAAAAAAAAAAAAAAA=="),
                                "Name" : null
                        }
                ],
                "CreatedOn" : [
                        NumberLong("635052144104050898"),
                        0
                ],
                "StartDateTime" : [
                        NumberLong("635052173400000000"),
                        0
                ]
        }
]

I realize that StartDateTime is stored as Ticks in MongoDB.

var dateMarker = DateTimeOffset.UtcNow;
var nextDay = dateMarker.AddDays(1);

This query does not work:

var today = EventRepoistory.All().Where(z => z.StartDateTime >= dateMarker && z.StartDateTime < nextDay).OrderByDescending(z => z.StartDateTime).ToList();

I have added a query display to the Mongo C# driver which shows the following query:

{ "$query" : { "StartDateTime" : { "$gte" : [NumberLong("635052168609734070"), 0], "$lt" : [NumberLong("635053032609734070"), 0] } }, "$orderby" : { "StartDateTime" : -1 } }

Lower bound = 6350521 68609734070

Server = 6350521 73400000000

Upper bound = 6350530 32609734070

Question: Why is MongoDB query not returning anything?

db.ScheduledEvent.find({ "$query" : { "StartDateTime" : { "$gte" : [NumberLong("635052168609734070"), 0], "$lt" : [NumberLong("635053032609734070"), 0] } }, "$orderby" : { "StartDateTime" : -1 } })

Researched:

MongoDB and DateTimeOffset type but it seams that LINQ provider is doing what it's supposed to?

Tried:

db.ScheduledEvent.find({ "StartDateTime" : { "$gte" : [NumberLong("1"), 0]  } }  )

produces no results.


回答1:


A similar answer is found here: MongoDB and DateTimeOffset type (as you note in your question)

I got this working with the C# Driver by doing the following:

var query = Query.GT("StartDateTime.0", startDate.Ticks);
var json = query.ToJson();

Produces this JSON:

{ "StartDateTime.0" : { "$gt" : NumberLong("635251617859913739") } }

The above JSON works. Per the linked answer the reason is that DateTimeOffset is an array.

When I use LINQ I get (as you noted) a different result for the JSON.

var query = from r in col.AsQueryable<MyObjectType>()
    where r.StartDateTime>= startDate && r.StartDateTime< endDate
    select r;

The LINQ query above produces the following JSON:

{ "StartDateTime" : { "$gte" : [NumberLong("635251617859913739"), 0], "$lt" : [NumberLong("635251635859913739"), 0] } }

I am not sure if the LINQ provider in the C# driver needs to be fixed to handle DateTimeOffset but using the Query builder to specify the first element of the DateTimeOffset array (StartDateTime.0) was the only way I got this working.




回答2:


As other answers state, the root cause of the problem is that DateTimeOffset fields are serialized as arrays (with ticks and offset) by default.

The answer proposed by dsandor works fine, if you are able to localize your changes in DAL layer and use queries specific to MongoDB.

However, such approach does not work well if your repository exposes IQueryable<ScheduledEvent> and some LINQ queries are applied in service layer.

The more generic approach is to change the way how DateTimeOffset fields are serialized to MongoDB, so that LINQ queries function correctly, without necessity for customization of MongoDB queries.

You can easily change the serialization of DateTimeOffset fields with BsonRepresentation(BsonType.String) attribute:

public class ScheduledEvent : Event
{
    [BsonRepresentation(BsonType.String)]
    public DateTimeOffset StartDateTime { get; set; }
}

In this case DateTimeOffset fields are saved to MongoDB in string form 2020-04-03T08:12:23+03:00 and LINQ queries work correctly.




回答3:


Use the following syntax in your query:

{
    "StartDateTime.0": {
        "$gte": 635052168609734070
    }
}


来源:https://stackoverflow.com/questions/16765543/properly-using-handling-datetimeoffset-in-mongodb

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!