J'utilise mongoDB c # dernier pilote, c'est-à-dire 3. + dans mon projet. J'ai différents critères de filtre de date comme aujourd'hui, dernier jour, hier, ce mois, etc. en utilisant daterangepicker.
Voici mon modèle
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; }
}
Voici le code du pilote
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();
Ce code fonctionne bien, mais lorsque je sélectionne le filtre d'aujourd'hui, la date devient
var start = new DateTime(2017, 03, 31);
var end = new DateTime(2017, 03, 31);
Il n'a pas retourné d'enregistrements pour la journée en cours. C'est aussi le calcul du temps.
J'enregistre les dates au format DateTime.Now. Exemple de date ISO que j'interroge sont
"CreatedOn": ISODate("2017-03-31T20:27:12.914+05:00"),
"ModifiedOn": ISODate("2017-03-31T20:27:12.914+05:00"),
C'est le filtre de dates que j'utilise. Dois-je avoir à soustraire -1 des dates de fin?
Besoin d'aide pour ce que je fais mal.
Je crois que vous vous confondez avec les fuseaux horaires, en particulier la partie décalée.
MongoDb enregistre toujours la date en heure UTC.
Ainsi, lorsque vous regardez l'heure de la date dans MongoDB, vous devez toujours prendre en compte le décalage par rapport à votre fuseau horaire local.
Vous enverrez toujours la date dans le fuseau horaire local. Le pilote Mongo C # change l'heure de locale à UTC avant de persister.
Par exemple
Lorsque j'enregistre le document avec CreatedOn = 2017-04-05 15:21:23.234
(Fuseau horaire local (Amérique/Chicago)) mais lorsque vous regardez les documents dans la base de données, vous verrez quelque chose ISODate("2017-04-05T20:21:23.234Z")
c'est-à-dire le décalage de l'heure locale par rapport à UTC qui est -5 heures.
[BsonDateTimeOptions(Kind = DateTimeKind.Local)]
indique au conducteur de convertir l'heure en heure locale à partir d'UTC lors du retrait du BSON vers votre POCO.
Voici le cas de test expliquant le comportement.
Code:
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; }
}
Collection: (vu à travers 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"
}
Mise à jour:
"CreatedOn": ISODate("2017-03-31T20:27:12.914+05:00")
La raison pour laquelle votre comparaison ne fonctionne pas est
var start = new DateTime(2017, 03, 31);
var end = new DateTime(2017, 03, 31);
Ceci est envoyé au serveur en tant que $gte
Que ISODate("2017-03-31T00:00:00.000+05:00")
et $lte
Que ISODate("2017-03-31T00:00:00.000+05:00")
et il ne trouve pas l'entrée ci-dessus.
La bonne façon d'interroger la date today
sera
var start = new DateTime(2017, 03, 31);
var end = new DateTime(2017, 04, 01);
et mettez à jour votre filtre
var filter = filterBuilder.Gte(x => x.CreatedOn, start) &
filterBuilder.Lt(x => x.CreatedOn, end);
Alors maintenant, votre requête de plage est envoyée au serveur sous la forme $gte
Que ISODate("2017-03-31T00:00:00.000+05:00")
et $lt
Que ISODate("2017-04-01T00:00:00.000+05:00")
et vous devriez pouvoir trouver toutes les correspondances pour aujourd'hui .
mise à jour 2
Modifiez votre base de données pour stocker la date et l'heure avec une partie d'heure définie sur 00:00:00. Cela supprimera également la partie temps de l'équation de la base de données et vos anciennes requêtes de plage fonctionneront très bien dans tous les cas.
Modifiez votre méthode de sauvegarde à utiliser
var today = DateTime.Today; //2017-03-31 00:00:00.000
Vous pouvez revenir à l'ancienne définition de filtre.
Quelque chose comme
var start = new DateTime(2017, 03, 31);
var end = new DateTime(2017, 03, 31);
et mettez à jour votre filtre
var filter = filterBuilder.Gte(x => x.CreatedOn, start) &
filterBuilder.Lte(x => x.CreatedOn, end);
Alors maintenant, votre requête de plage est envoyée au serveur sous la forme $gte
Que ISODate("2017-03-31T00:00:00.000+05:00")
et $lte
Que ISODate("2017-03-31T00:00:00.000+05:00")
et vous devriez pouvoir trouver toutes les correspondances pour aujourd'hui .
Mise à jour - Comparaison de la date uniquement à l'aide de BsonDocument
.
L'idée ici est d'ajouter un décalage de fuseau horaire qui est +5:00
À la date UTC du serveur et de transformer le datetime calculé au format chaîne yyyy-MM-dd
En utilisant l'opérateur $dateToSting
Suivi d'une comparaison sur la date de la chaîne d'entrée dans le même format.
Cela fonctionnera dans votre fuseau horaire mais ne fonctionnera pas dans DST en observant les fuseaux horaires.
Mongo version 3.4
Vous pouvez utiliser l'étape $addFields
Qui ajoute un nouveau champ CreatedOnDate
tout en conservant toutes les propriétés existantes et dernier $project
Pour supprimer le CreatedOnDate
de la réponse finale après comparaison.
Requête 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
}
}
Code 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<BsonDocument>(addFields)
.Match(match)
.Project(project);
var list = pipeline.ToList();
List<Student> searchResult = list.Select(doc => BsonSerializer.Deserialize<Student>(doc)).ToList();
Version Mongo = 3.2
Comme ci-dessus, mais ce pipeline utilise $project
, Vous devrez donc ajouter tous les champs que vous souhaitez conserver dans la réponse finale.
Requête 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
}
}
Code 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<Student> searchResult = list.Select(doc => BsonSerializer.Deserialize<Student>(doc)).ToList();
Mise à jour 4 - Comparaison de la date uniquement qui fonctionne avec les économies de lumière du jour.
Version Mongo = 3.6
Tout reste le même, attendez-vous à ce que $dateToString
Prenne le fuseau horaire au lieu d'un décalage fixe qui devrait prendre en compte les changements d'heure d'été.
Mise à jour du shell:
{
"$addFields": {
"CreatedOnDate": {
"$dateToString": {
"format": "%Y-%m-%d",
"date": "$CreatedOn",
"timezone": "America/New_York"
}
}
}
}
Mise à jour C #:
var addFields = BsonDocument.Parse("{$addFields: { CreatedOnDate: { $dateToString: { format: '%Y-%m-%d', date: "$CreatedOn", "timezone": "America/New_York"} }} }");
Ce qui suit affichera votre accessoire POCO
private DateTime _ShortDateOnly;
[BsonElement("ShortDateOnly")]
[BsonDateTimeOptions(DateOnly = true)]
public DateTime ShortDateOnly {
set { _ShortDateOnly = value; }
get { return _ShortDateOnly.Date; }
}
Je l'ai utilisé pour créer le DOCUMENT BSON suivant
{{
"_id" : CSUUID("12ce2538-2921-4da0-8211-9202da92d7f3"),
"first" : "Felipe",
"New" : "Ferreira",
"PublicPassword" : null,
"netWorth" : "20000.99",
"netWorth2" : 20000.990000000002,
"UserType" : "Admin",
"BirthDate" : ISODate("2019-06-22T18:59:01.861Z"),
"ShortDateOnly" : ISODate("2019-06-22T00:00:00Z")
}}
Souhaitez-vous bien vouloir ajouter ce qui suit à votre POCO et me faire savoir si cela a été au minimum suffisant pour que cela fonctionne pour vous?