我使用Newtonsoft JsonTextWriter手动序列化大量POCO并将结果保存为MongoDB BsonDocument。
//
// POCO to store in MongoDB
public class Session
{
public DateTime? StartUTCTimestamp { get; set; }
public DateTime? StartTimestamp { get; set; }
public DateTime? EndTimestamp { get; set; }
public void ToJSON(ref JsonTextWriter writer)
{
Session session = this;
writer.WriteStartObject(); // {
writer.WritePropertyName("StartUTCTimestamp");
writer.WriteValue(session.StartUTCTimestamp);
writer.WritePropertyName("StartTimestamp");
writer.WriteValue(session.StartTimestamp);
writer.WritePropertyName("EndTimestamp");
writer.WriteValue(session.EndTimestamp);
writer.WriteEndObject(); // }
}
}
测试应用程序中用于导入数据的方法,从SQL Server数据库中检索所有 Session 对象(使用Telerik的Open Access ORM),将结果存储在名单。我通过调用POCO上定义的ToJSON()方法(见上文)序列化每个Session,并传入对JsonTextWriter的引用。然后使用C#MongoDB驱动程序将生成的JSON字符串反序列化为BsonDocument,然后将其保存到Mongo。 (以下示例来自ASP.NET Web窗体页面,因此警报框用户控件)。
private void LoadData()
{
DateTime startDate = new DateTime(2015,12,31,23,59,59);
var collection = _database.GetCollection<BsonDocument>("sessions");
using (DbContext ctx = new DbContext())
{
List<Session> sessions = ctx.Sessions.Where().ToList();
foreach (Session item in sessions)
{
JsonTextWriter writer = null;
try
{
StringWriter sw = new StringWriter();
writer = new JsonTextWriter(sw);
writer.CloseOutput = true;
item.ToJSON(ref writer);
String json = sw.ToString();
BsonDocument doc = MongoDB.Bson.Serialization.BsonSerializer.Deserialize<BsonDocument>(json);
collection.InsertOne(doc);
this.ucAlertMsg.Show("bg-info", "Completed without exception");
}
catch (Exception ex)
{
while (ex.InnerException != null) { ex = ex.InnerException; }
this.ucAlertMsg.Show("bg-danger", ex.Message);
}
finally
{
writer.Close();
}
}
}
}
这样可以保存文档,但是,我无法有效地查询文档,在日期范围内进行过滤。我相信,根据我读过的其他几篇文章和文章,这可能是因为该值存储为字符串而不是&#34; ISODate()&#34;。
//
// This is what IS saved
{
"_id" : ObjectId("5729128cd9017a248cbe6284"),
"StartUTCTimestamp" : "2015-12-15T23:24:06",
"StartTimestamp" : "2015-12-15T18:24:06",
"EndTimestamp" : "2015-12-15T18:26:59",
}
//
// Is this what I need?
{
"_id" : ObjectId("5729128cd9017a248cbe6284"),
"StartUTCTimestamp" : ISODate("2015-12-15T23:24:06"),
"StartTimestamp" : ISODate("2015-12-15T18:24:06"),
"EndTimestamp" : ISODate("2015-12-15T18:26:59"),
}
在我的LoadData()方法中,我在TextWriter上尝试了很多配置,根据我读过的一些文章看起来应该有帮助......
StringWriter sw = new StringWriter();
writer = new JsonTextWriter(sw);
writer.DateFormatHandling = DateFormatHandling.IsoDateFormat;
writer.CloseOutput = true;
分配&#34; IsoDateFormat&#34;到&#34; DateFormatHanding&#34;对作家的设定没有产生任何影响。我也试过&#34; MicrosoftDateFormat&#34;并且数据仍然存储为字符串,但格式不同。
实际问题
这就是所有的设置......问题是&#34;如何根据日期搜索MongoDB文档&#34;?
使用MongoDB的C#驱动程序允许我使用Linq进行搜索。这是我正在使用的linq查询。
IMongoCollection<Session> collection = database.GetCollection<Session>("sessions");
DateTime startDate = (this.StartDate.HasValue) ? this.StartDate.Value : DateTime.Now.AddDays(-7);
DateTime endDate = (this.EndDate.HasValue) ? this.EndDate.Value : DateTime.Now;
var data = collection.Find<Session>(e => e.StartTimestamp.Value >= startDate && e.StartTimestamp.Value <= endDate).ToList();
由于JSON直接映射回Session POCO,我应该可以使用该类型(?)。我可以成功过滤Session POCO中的其他字段。它只是让我适应的日期。
我猜测我的实现中存在某些不妥或疏忽,或者由于数据存储为字符串,因此无法将其作为日期(?)进行比较。
非常感谢任何见解。
谢谢, -G
答案 0 :(得分:2)
没有多少人看过这篇文章,所以也许我对它的评价很差,但对于那个赞成它的人来说,我确实来到了我认为更像是&#34;工作周期&#34;而不是一个实际的解决方案,但也许它也会帮助你。
取代或除了以典型的字符串格式保存日期(&#34; yyy / MM / dd HH:mm:ss&#34;),我将日期保存为Int64的蜱即可。解析器/编写器将这些识别为数字并将其存储为数字。当然,数字很容易排序和排序。
所以原帖的 Session 模型现在看起来像这样......
//
// POCO to store in MongoDB
public class Session
{
public DateTime? StartUTCTimestamp { get; set; }
public DateTime? StartTimestamp { get; set; }
public DateTime? EndTimestamp { get; set; }
//
// If the StartUTCDate is defined then return the number of "ticks" in the date
[BsonElement("StartUTCTimestampTicks")]
public Int64? StartUTCTimestampTicks
{
get
{
return (this.StartUTCTimestamp.HasValue) ?
(Int64?)this.StartUTCTimestamp.Value.Ticks :
null;
}
}
//
// If the StartDate is defined then return the number of "ticks" in the date
[BsonElement("StartTimestampTicks")]
public Int64? StartTimestampTicks
{
get
{
return (this.StartTimestamp.HasValue) ?
(Int64?)this.StartTimestamp.Value.Ticks :
null;
}
}
//
// If the EndDate is defined then return the number of "ticks" in the date
[BsonElement("EndTimestampTicks")]
public Int64? EndTimestampTicks
{
get
{
return (this.EndTimestamp.HasValue) ?
(Int64?)this.EndTimestamp.Value.Ticks :
null;
}
}
public void ToJSON(ref JsonTextWriter writer)
{
Session session = this;
writer.WriteStartObject(); // {
if (session.StartUTCTimestamp.HasValue)
{
writer.WritePropertyName("StartUTCTimestamp");
writer.WriteValue(session.StartUTCTimestamp);
writer.WritePropertyName("StartUTCTimestampTicks");
writer.WriteValue(session.StartUTCTimestampTicks);
}
if (session.StartTimestamp.HasValue)
{
writer.WritePropertyName("StartTimestamp");
writer.WriteValue(session.StartTimestamp);
writer.WritePropertyName("StartTimestampTicks");
writer.WriteValue(session.StartTimestampTicks);
}
if (session.EndTimestamp.HasValue)
{
writer.WritePropertyName("EndTimestamp");
writer.WriteValue(session.EndTimestamp);
writer.WritePropertyName("EndTimestampTicks");
writer.WriteValue(session.EndTimestampTicks);
}
writer.WriteEndObject(); // }
}
}
如果已定义,我已添加了显示每个日期中刻度数的属性。如果不是,他们只返回 null 。我必须使用 BsonElement 属性来装饰它们,以使它们能够被JsonTextWriter识别(不确定为什么这些需要它而其他属性没有),否则我收到错误。
我还修改了模型上的ToJSON()方法,以检查在序列化值之前是否提供了日期。如果未定义日期,那么我们不会将json元素添加到文档中。
存储在MongoDB中的结果文档现在看起来像......
{
"_id" : ObjectId("572b4486d9016b151846b8ed"),
"StartUTCTimestamp" : "2016-04-24T17:02:12",
"StartUTCTimestampTicks" : NumberLong(635971141320000000),
"StartTimestamp" : "2016-04-24T13:02:12",
"StartTimestampTicks" : NumberLong(635970997320000000),
"EndTimestamp" : "2016-04-24T13:05:16",
"EndTimestampTicks" : NumberLong(635970999160000000)
}
为什么这些值存储在&#34; NumberLong()&#34;数据类型函数和日期不存储在&#34; ISODate()&#34;函数对我来说是一个谜,但它现在允许我根据Ticks而不是日期字符串查询日期和日期范围。
IMongoCollection<Session> collection = database.GetCollection<Session>("sessions");
DateTime startDate = (this.StartDate.HasValue) ? this.StartDate.Value : DateTime.Now.AddDays(-7);
DateTime endDate = (this.EndDate.HasValue) ? this.EndDate.Value : DateTime.Now;
var data = collection.Find<Session>(e => e.StartTimestampTicks.Value >= startDate.Ticks && e.StartTimestampTicks.Value <= endDate.Ticks).ToList();
这实际上让我考虑不保存日期字符串。我将它们更多地保留为标签,因为它们在查看实际的JsonDocument时更具可读性。但是,只要通过用户界面查看文档的主要用途,将Ticks转换为更易读的日期字符串表示是一件微不足道的事情。
无论如何......我希望这有帮助...有人...... :)
答案 1 :(得分:2)
必须使用BsonValue.Create(yourDate)创建过滤器表达式中的日期;
示例:
IMongoDatabase db = GetMongoDbConnection();
IMongoCollection<BsonDocument> collection = db.GetCollection<BsonDocument> ("yourCollectionName");
DateTime date = BsonValue.Create(DateTime.Now.Date);
var filter = Builders<BsonDocument>.Filter.Gt("dateFieldToFilterOn", date);
List<BsonDocument> bsonDocuments = await collection.Find(filter).ToListAsync();