Правильное использование / обработка DateTimeOffset в MongoDB

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

StartDateTime = 27.05.2013 2:09:00 +00:00, представляющий 26.05.2013, 19:09 PST

Что записано в 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
                ]
        }
]

Я понимаю, что StartDateTime хранится в виде тиков в MongoDB.

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

Этот запрос не работает:

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

Я добавил отображение запроса в драйвер Mongo C#, который показывает следующий запрос:

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

Нижняя граница = 6350521 68609734070

Сервер = 6350521 73400000000

Верхняя граница = 6350530 32609734070

Вопрос: Почему запрос MongoDB ничего не возвращает?

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

Исследуемый:

Тип MongoDB и DateTimeOffset, но он показывает, что поставщик LINQ делает то, что должен?

Пытался:

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

не дает результатов.

2 ответа

Решение

Подобный ответ находится здесь: MongoDB и тип DateTimeOffset (как вы отметили в своем вопросе)

Я получил это, работая с драйвером C#, выполнив следующие действия:

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

Производит этот JSON:

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

Выше JSON работает. Согласно связанному ответу причина в том, что DateTimeOffset является массивом.

Когда я использую LINQ, я получаю (как вы заметили) другой результат для JSON.

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

Приведенный выше запрос LINQ создает следующий JSON:

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

Я не уверен, нужно ли исправлять поставщика LINQ в драйвере C# для обработки DateTimeOffset, но использование конструктора запросов для указания первого элемента массива DateTimeOffset (StartDateTime.0) было единственным способом, которым я получил эту работу.

Как утверждают другие ответы, основная причина проблемы заключается в том, что DateTimeOffset поля по умолчанию сериализуются как массивы (с отметками и смещением).

Ответ, предложенный dsandor, отлично работает, если вы можете локализовать свои изменения в слое DAL и использовать запросы, специфичные для MongoDB.

Однако такой подход не работает, если в вашем репозитории есть IQueryable<ScheduledEvent> и некоторые запросы LINQ применяются на уровне обслуживания.

Более общий подход - изменить способ DateTimeOffset Поля сериализуются в MongoDB, чтобы запросы LINQ работали правильно, без необходимости настройки запросов MongoDB.

Вы можете легко изменить сериализацию DateTimeOffset поля с BsonRepresentation(BsonType.String) атрибут:

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

В этом случае DateTimeOffset поля сохраняются в MongoDB в строковой форме 2020-04-03T08:12:23+03:00 и запросы LINQ работают правильно.

Используйте следующий синтаксис в вашем запросе:

{
    "StartDateTime.0": {
        "$gte": 635052168609734070
    }
}
Другие вопросы по тегам