2016-05-04 13 views
1

Newtonsoft JsonTextWriterを使用していくつかのPOCOを手動でシリアル化し、結果をMongoDB BsonDocumentとして保存しています。C#ドライバを使用してMongoDBの日付フィールドをフィルタリングできません

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

データをインポートするために使用される試験アプリケーションの方法は、リストの結果を格納する(TelerikのオープンアクセスORMを使用して)SQL Serverデータベースからのすべてのセッションオブジェクトを検索します。私は各セッションをPOCO(上を参照)で定義されたToJSON()メソッドを呼び出し、JsonTextWriterへの参照を渡してシリアル化します。結果のJSON文字列は、C#MongoDBドライバを使用して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(); 
      } 
     } 
    } 
} 

これは文書をうまく保存していますが、日付範囲をフィルタリングして文書を効果的にクエリできません。私は、読んだ他のいくつかの記事と記事に基づいて、値が "ISODate()"ではなく文字列として保存されている可能性があると考えています。私はそれが役立っている必要がありますように、私が読んだ記事の一部に応じらしいたTextWriter上の多数の構成を試してみましたが、私のloaddataの()メソッドで

// 
// 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"), 
} 

...

StringWriter sw    = new StringWriter(); 
writer      = new JsonTextWriter(sw); 
writer.DateFormatHandling = DateFormatHandling.IsoDateFormat; 
writer.CloseOutput   = true; 

ライターの "DateFormatHanding"設定に "IsoDateFormat"を割り当てると、違いはありません。私も "MicrosoftDateFormat"を試してみましたが、データはまだ文字列として保存されていましたが、形式が異なりました。

実際の質問

は、だから、すべての設定だ...質問は、「どのように私は日付に基づいてMongoDBのドキュメントを検索します」ですか?

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はセッションPOCOに直接マッピングされるので、そのタイプ(?)を使用できるはずです。セッションPOCOの他のフィールドを正常にフィルタリングできます。それはちょうど私のフィット感を与えている日付です。

私の実装に何か不安や見落としがあると推測しています。データが文字列として保存されているため、日付(?)と比較できません。

洞察力があれば幸いです。

おかげで、 -G

答えて

1

多くの人々は、このポストはので、おそらく私は悪いそれをタグ付けしている見てきましたが、それをupvoted一人のために私はより多くの「回避」と見なすものaccrossに来なかったの実際の解決策よりも優れていますが、おそらくそれはあなたにも役立ちます。

代わりの

、または一般的な文字列の形式で日付をを保存するだけでは、Int64型をティックとして( "YYY/MM/DD HH:MM:SS")、私は日付を救いました。パーサー/ライターはこれらを数字として認識し、そのように保存します。もちろん、数値は簡単にソートして並べ替えることができます。

だから、オリジナルのポストからセッションモデルは次のようになります...

// 
// 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の中に保存された文書は、今のように見える

...これらの値は、「NumberLong()」データ型の機能で保存されていると、日付が「ISODateに保存されていないのはなぜ

{ 
    "_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) 
} 

() "関数は私にとって謎ですが、日付文字列ではなく、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を読みやすい日付文字列表現に変換するのは些細なことです。

とにかく...私はこのヘルプを願っています...誰か...あなたのフィルター式で:)

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(); 
関連する問題