Saltar al contenido

Filtrar solo por fecha usando el controlador mongoDB c #

Ya no necesitas investigar más en otras webs porque llegaste al espacio necesario, poseemos la solución que deseas y sin complicarte.

Solución:

Creo que se está confundiendo con las zonas horarias, especialmente con la parte de compensación.

MongoDb siempre guarda la fecha en hora UTC.

Entonces, cuando mira la fecha y hora en MongoDB, siempre debe tener en cuenta el desplazamiento de su zona horaria local.

Siempre enviará la fecha en la zona horaria local. El controlador Mongo C # cambia la hora de local a UTC antes de persistir.

Por ejemplo

Cuando guardo el documento con CreatedOn = 2017-04-05 15:21:23.234 (zona horaria local (América / Chicago)) pero cuando mire los documentos en la base de datos verá algo ISODate("2017-04-05T20:21:23.234Z") es decir, la diferencia de hora local con respecto a UTC es de -5 horas.

[BsonDateTimeOptions(Kind = DateTimeKind.Local)] indica al conductor que convierta la hora a la hora local de UTC cuando descarrile el BSON de nuevo a su POCO.

Aquí está el caso de prueba que explica el comportamiento.

Codigo:

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("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 StudentDescription = "today", CreatedOn = today,
            new StudentDescription = "yesterday", CreatedOn = yesterday,
            
         );

        var filterBuilder1 = Builders.Filter;
        var filter1 = filterBuilder1.Eq(x => x.CreatedOn, today);
        List searchResult1 = collection.Find(filter1).ToList();

        Console.Write(searchResult1.Count == 1);

        var filterBuilder2 = Builders.Filter;
        var filter2 = filterBuilder2.Eq(x => x.CreatedOn, yesterday);
        List 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; 

Colección: (cuando se ve a través de la cáscara de mongo)


        "_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"

Actualizar :

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

La razón por la que su comparación no funciona es

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

Esto se envía al servidor como $gte que ISODate("2017-03-31T00:00:00.000+05:00") y $lte que ISODate("2017-03-31T00:00:00.000+05:00") y no encuentra la entrada anterior.

La forma correcta de consultar today la fecha será

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

y actualice su filtro para

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

Así que ahora su consulta de rango se envía al servidor como $gte que ISODate("2017-03-31T00:00:00.000+05:00") y $lt que ISODate("2017-04-01T00:00:00.000+05:00") y debería poder encontrar todas las coincidencias para hoy.

Actualización 2

Cambie su base de datos para almacenar la fecha y la hora con la parte de la hora establecida en 00:00:00. Esto también eliminará la parte de tiempo de la ecuación de db y sus consultas de rango anteriores funcionarán bien en todos los casos.

Cambie su método de guardado para usar

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

Puede volver a la definición de filtro anterior.

Algo como

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

y actualice su filtro para

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

Entonces ahora su consulta de rango se envía al servidor como $gte que ISODate("2017-03-31T00:00:00.000+05:00") y $lte que ISODate("2017-03-31T00:00:00.000+05:00") y debería poder encontrar todas las coincidencias para hoy.

Actualización 3 – Comparación de solo fecha usando BsonDocument.

La idea aquí es agregar un desplazamiento de zona horaria que es +5:00 a la fecha UTC del servidor y transforme la fecha y hora calculada en string yyyy-MM-dd formato usando $dateToSting operador seguido de comparación en la entrada string fecha en el mismo formato.

Esto funcionará en tu zona horaria, pero no funcionará en horario de verano observando las zonas horarias.

Mongo Versión 3.4

Puedes usar $addFields etapa que agrega un nuevo campo CreatedOnDatemanteniendo todas las propiedades existentes y por último $project dejar caer el CreatedOnDate de la respuesta final después de la comparación.

Consulta de 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
    

Código 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(addFields)
    .Match(match)
    .Project(project);

var list = pipeline.ToList();

List searchResult = list.Select(doc => BsonSerializer.Deserialize(doc)).ToList();

Versión de Mongo = 3.2

Igual que el anterior, pero esta canalización utiliza $project por lo que tendrá que agregar todos los campos que desea mantener en la respuesta final.

Consulta de 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
    

Código 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 searchResult = list.Select(doc => BsonSerializer.Deserialize(doc)).ToList();

Actualización 4 – Comparación de solo fecha que funciona con el horario de verano.

Versión de Mongo = 3.6

Todo permanece igual, espera $dateToString tomará la zona horaria en lugar de la compensación fija que debería tener en cuenta los cambios de horario de verano.

Actualización de Shell:


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

Actualización de C #:

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

Si guardas alguna desconfianza y disposición de mejorar nuestro artículo te recomendamos dejar una interpretación y con mucho placer lo observaremos.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *