Mongo Builder在`DateTime`类字段中使用`String`

时间:2018-08-30 17:48:35

标签: c# mongodb mongodb-query

我有一个类别为DateTime的类:

class Model {
    public DateTime Date { get; set; }
}

在mongo数据库中,它存储为:

"Date" : "2018-02-01T13:22:08Z"

代码:

var builder = Builders<Model>.Filter;

var filter = builder.In("Date", new[]
            {
               "2018-02-01T13:22:08Z"
            });

// Returns zero element list
_collection.Find(filter).ToList();

有趣的是:

  var workingFilter = new BsonDocument()
        {
            { "Date", "2018-02-01T13:22:08Z"}
        };

// This one actually works
_collection.Find(workingFilter).ToList();

我认为当我提供Builder作为string字段的值来查询时,Mongo的DateTime实用程序存在问题。

2 个答案:

答案 0 :(得分:1)

首先,您的.NET DateTime存储为MongoDB string,这不是默认行为。默认情况下,您应该能够在数据库中看到类似这样的内容:

"Date" : ISODate("2018-02-01T13:22:08Z")

因此,数据库中存储的类型与模型中的类型之间不匹配。请记住,MongoDB在值之前检查类型,并且没有像JavaScript那样的隐式强制转换。

在您的工作示例中,您使用了handles dynamic documentsBsonDocument,因此驱动程序只是忽略了模型中指定的数据类型,并将其转换为

db.yourCollection.find({"Date" : "2018-02-01T13:22:08Z"})

并返回该文档。

第二个代码段使用通用的Filter Builder,因此您指定要关心Model类中的类型。

您可以在2级上启用MongoDB分析器,然后运行.NET代码:

db.setProfilingLevel(2)

然后,您可以在数据库上运行以下查询:

db.system.profile.find({ns: "yourdb.yourcollection"}).sort({ts:-1}).limit(1).pretty()

,您将看到由驱动程序生成的查询:

"command" : {
            "find" : "yourcollection",
            "filter" : {
                    "Date" : {
                            "$in" : [
                                    ISODate("2018-02-01T13:22:08Z")
                            ]
                    }
            },
            "$db" : "yourdb"
    }

因此,您可以看到驱动程序知道DateTime并将字符串转换为ISODate,这会导致数据库查询级别的类型不匹配,这就是为什么没有得到结果的原因。

解决方案?将您的.NET DateTime作为ISODate存储在MongoDB中(推荐),或者始终使用BsonDocument来构建查询。

答案 1 :(得分:-1)

在C#中使用BsonDateTime代替DateTime。如果您想向C#用户公开.NET DateTime,并且仍将日期作为Mongo中的日期持久化,请创建针对同一后备存储获取/设置的两个属性,并使用某些Mongo属性不持久化本机DateTime和重命名BsonDateTime。