2017-04-02 17 views
7

Używam najnowszego sterownika mongoDB C#, tj. 3. + w moim projekcie. Mam różne kryteria filtrowania daty, takie jak Dzisiaj, Ostatni dzień, Wczoraj, W tym miesiącu itp. Za pomocą daterangepicker.Filtruj tylko według daty używając mongoDB C# driver

Oto mój model

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; } 
    } 

Oto kod kierowca

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(); 

Ten kod działa poprawnie, ale gdy wybiorę dzisiejszym filtrować wtedy data staje

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

To nie zrobił 't zwraca rekordy dla bieżącego dnia. To także obliczanie czasu.

Zapisuję daty jako DateTime.Now. Przykładowa data ISO, której dotyczy zapytanie, to:

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

To jest filtr dat, którego używam. Czy muszę odstąpić -1 od dat końcowych? enter image description here

Potrzebujesz pomocy, co robię źle.

+0

można dodać przykładowy dokument ze swojej kolekcji, które oczekują zapytanie dla bieżącego dnia do powrotu? – Veeram

+0

Zapisuję DateTime.Now w bazie danych zobacz moje edytowane pytanie –

+0

Thanls @Veeram dla dzisiejszych przykładów Mogę używać metod AddDays, ale co z innymi, mam aktualizacje filtra dla dat, które mam. Potrzebujesz jakiegoś ogólnego rozwiązania. –

Odpowiedz

-1

Podczas korzystania

new DateTime(2017, 03, 31); 

uzyskać obiekt DateTime, co oznacza, że ​​obliczenia czasu również. Tak, przy użyciu tego samego parsowania dla obu start i stop, to rzeczywiście coś równą:

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

Jasne, to prawdopodobnie nie masz rekord pod tym konkretnym przedziale czasowym. W przypadku naprawdę chcesz uzyskać wszystkie dzisiejszą rekord, należy zrobić coś takiego:

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

Nie ma przeciążenia, aby wziąć argument ciągu .. –

+0

@GhazanfarKhan On jest tutaj, aby ci pomóc. Jeśli się myli, po prostu daj mu znać. Nie trzeba używać takiego języka. Nadzieję, że rozumiecie. – Sachin

+0

Mam to, ale nie spodziewałem się tego. –

2

wierzę, że są coraz mylić ze stref czasowych zwłaszcza przesunięcie części.

MongoDb zawsze zapisuje datę w czasie UTC.

Tak więc, gdy patrzysz na datę w MongoDB, zawsze musisz wziąć pod uwagę offset w swojej lokalnej strefie czasowej.

Zawsze będziesz wysyłać datę w lokalnej strefie czasowej. Sterownik Mongo C# zmienia czas z lokalnego na UTC przed kontynuowaniem.

Na przykład

Kiedy zapisać dokument z CreatedOn = 2017-04-05 15:21:23.234 (lokalnej strefy czasowej (Ameryka/Chicago)), ale jeśli spojrzeć na dokumentach w DB będzie można zobaczyć coś ISODate("2017-04-05T20:21:23.234Z") czyli czas lokalny przesunięcie od UTC, który jest -5 godzin.

[BsonDateTimeOptions(Kind = DateTimeKind.Local)] wskazuje kierowcy, aby zamienić czas na czas lokalny od czasu UTC, gdy ponownie wysyłasz BSON z powrotem do POCO.

Oto przypadek testowy wyjaśniający zachowanie.

Kod:

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; } 
} 

Kolekcja: (patrząc przez 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" 
} 

Aktualizacja:

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

Powód twoje porównanie nie działa to

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

To dostaje wysłać do serwera tak jak $gte niż ISODate("2017-03-31T00:00:00.000+05:00") i $lte niż ISODate("2017-03-31T00:00:00.000+05:00") i robi znaleźć powyższego wpisu.

Właściwy sposób do kwerendy dla today bieżąco będzie

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

i zaktualizować filtr

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

więc teraz zapytanie zakres jest wysyłanie do serwera jako $gte niż ISODate("2017-03-31T00:00:00.000+05:00") i $lt niż ISODate("2017-04-01T00:00:00.000+05:00") i powinieneś być w stanie znaleźć wszystkie mecze na dziś.

Aktualizacja 2

zmienić bazę danych do przechowywania czasu daty z częścią zestawu czasu do 00:00:00. Spowoduje to również usunięcie części czasu z równania z db, a twoje stare zapytania o pasmo będą działać dobrze dla wszystkich przypadków.

Zmień swoją zapisać metoda,

var today = DateTime.Today; //2017-03-31 00:00:00.000 

Można wrócić do starej definicji filtra.

Coś

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

i zaktualizować filtr do

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

Więc teraz zapytanie zakres jest wysyłanie do serwera jako $gte niż ISODate("2017-03-31T00:00:00.000+05:00") i $lte niż ISODate("2017-03-31T00:00:00.000+05:00") i powinieneś być w stanie znaleźć wszystko mecze na dziś.

Aktualizacja 3 - Porównanie tylko z datą przy użyciu BsonDocument.

Chodzi o to, aby dodać strefy czasowej, która jest +5:00 aktualne UTC serwera i przekształcić na format datetime obliczoną ciąg yyyy-MM-dd wykorzystaniem $dateToSting operatora następuje przez porównanie z datą ciąg wejściowy w tym samym formacie.

To zadziała w Twojej strefie czasowej, ale nie będzie działać w DST przestrzegając stref czasowych.

Mongo Wersja 3,4

Można użyć $addFields etap, który dodaje nowe pole CreatedOnDate zachowując wszystkie istniejące właściwości i ostatni $project upuścić CreatedOnDate od ostatecznej odpowiedzi po stosunku.

Shell Zapytanie:

{ 
    "$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# Kod:

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(); 

Mongo Version = 3,2

samo jak powyżej, ale ten rurociąg wykorzystuje $project więc musisz dodać wszystkie pola, które chcesz zachować w ostatecznej odpowiedzi.

Shell Zapytanie:

{ 
    "$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# Kod:

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(); 

Update 4 - tylko Data porównanie, który współpracuje z oszczędności światła dziennego.

Mongo Version = 3,6

Wszystko pozostaje takie same oczekiwać $dateToString odbędzie strefę czasową zamiast stałe przesunięcie, które powinny dbać o dziennych zmian oszczędzania światła pod uwagę.

Shell Aktualizacja:

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

C# Update:

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

Chcę przechowywać część czasu również jak używać z twoją odpowiedzią, nie używasz DateTime.Now –

+0

Dodano część czasu do przykładu. Użyj 'filterDefinition' z' Update' części odpowiedzi na zapytania porównawcze. – Veeram

+0

Gdybym musiał odfiltrować daty po stronie serwera, niż to, co używa daterangepicker. Czy mogę to zrobić po stronie klienta? –