Невозможно отфильтровать столбец даты, который хранится в виде строки в Mongo DB

#c# #mongodb #.net-core

#c# #mongodb #.net-core

Вопрос:

У меня есть приложение, которое записывает данные в MONGODB.
В документе у меня есть поле с именем updatedOn. В этом я пишу datetime в строковом формате, как показано ниже:

 DateTime.Now.ToString("MM/dd/yyyy HH:mm:ss")
  

Я знаю, что мне следовало использовать только тип даты, сейчас это хранится в базе данных в виде строки.
Теперь я получил требование фильтровать данные на основе этого поля между двумя датами.
Скажите что-то вроде этого :
Дата начала: «01/01/2019»
Дата окончания: «31/01/2019»

Это код, который я использовал ниже (который не работает)

 IMongoCollection<Order> OrderCollection = GetOrderCollection();
List<OrderFilter> lstJobs;

FilterDefinitionBuilder<Order> OrderFilter = Builders<Order>.Filter;

DateTime start = Convert.ToDateTime("01/01/2019");   
DateTime end = Convert.ToDateTime("31/01/2019");

var filter = OrderFilter.Gte("UpdatedOn", start) amp;
OrderFilter.Lt("UpdatedOn", end);

var fields = Builders<Order>.Projection.Include(p => p.Id);
lstOrders = await OrderCollection.Find(filter).Project<OrderFilter>(fields).ToListAsync<OrderFilter>().ConfigureAwait(false);
  

Класс OrderFilter:

 public class OrderFilter
{    
   [DataMember(Name = "id")]
   public string Id { get; set; }
}
  

Класс заказа:

 public class Order
{
   [DataMember(Name = "id")]
   public string Id { get; set; }

   [DataMember(Name = "UpdatedOn")]
   public string UpdatedOn { get; set; }
}
  

Поскольку updatedOn является строкой, и уже были вставлены некоторые данные. Это нецелесообразно изменять.

Кто-нибудь может помочь мне выполнить фильтрацию в этом случае. Есть ли какие-либо типизации или преобразования, которые я могу выполнить в самом коде и выполнить фильтрацию.
Большое спасибо!

Комментарии:

1. для начала измените DateTime start = Convert.ToDateTime("01/01/2019"); на DateTime start = Convert.ToDateTime("2019/01/01") , чтобы избежать неоднозначности дня и месяца

2. @JohnB Я сделал. Хотя это не помогло

Ответ №1:

Вам нужно будет проанализировать строку по дате, чтобы иметь возможность сравнивать с ней другие даты. Смотрите документы здесь.

Чтобы иметь возможность делать это на C #, вам придется использовать агрегированный метод, подобный этому:

 DateTime start = Convert.ToDateTime("01/01/2019");   
DateTime end = Convert.ToDateTime("31/01/2019");

var projectionDefinition = 
Builders<BsonDocument>.Projection.Exclude("convertedDate");

OrderCollection.Aggregate().AppendStage<BsonDocument>("{ $addFields: {convertedDate: { $toDate: '$UpdatedOn' }}}").Match(
    Builders<BsonDocument>.Filter.Gte(x => x["convertedDate"], new BsonDateTime(start))
    amp; Builders<BsonDocument>.Filter.Lte(x => x["convertedDate"], new BsonDateTime(end)))
    .Project(projectionDefinition).As<Order>();
  

Вероятно, вы сможете сделать это намного красивее, используя этапы.

Например,

 var projectionDefinition = Builders<BsonDocument>.Projection.Exclude("convertedDate");
var expression = new BsonDocument(new List<BsonElement>
{
    new BsonElement("convertedDate", new BsonDocument(new BsonElement("$toDate", "$UpdatedOn")))
});

var addFieldsStage = new BsonDocument(new BsonElement("$addFields", expression));

var gteFilter = Builders<BsonDocument>.Filter.Gte(x => x["convertedDate"], new BsonDateTime(startDate));
var lteFilter = Builders<BsonDocument>.Filter.Lte(x => x["convertedDate"], new BsonDateTime(endDate));

var combinedFilter= Builders<BsonDocument>.Filter.And(gteFilter, lteFilter);

var result = coll.Aggregate().AppendStage<BsonDocument>(addFieldsStage).Match(combinedFilter).Project(projectionDefinition).As<Order>();
  

И если вы добавите [BsonIgnoreExtraElements] выше своего класса, вы сможете отказаться от этапа проектирования.

Или в вашем случае, вероятно, просто замените его проекцией, которую вы используете в данный момент, и установите .As<Type> соответствующим образом.