10genからのMongoDBおよびC#ドライバー、明らかでない点



カットの下で、オブジェクトの部分的な読み込み、それに埋め込まれた配列の要素、およびいくつかの識別子によるオブジェクトの検索。 どういうわけかこれがどのように機能するかを調査するために私を連れ去り、実際のプロジェクトでMongoDBを使用するときにドライバーのソースコードを掘り下げることがありました。



mongodbに関する最初の投稿の後、数週間f#に切り替えましたが、戻ったとき、すべてが忘れられていることに気付きました。 私は自分の投稿を読み直さなければなりませんでした。明らかに、 Dmitry Nesterukでさえ私を平手打ちしたため、mongoを分解する必要はないようです。 叙情的な余談は終わりました。 この記事では、前の記事と同様に、すぐに予約を行います。これについては、Mongo Webサイトにあるリンクについて説明します。これは10genのドライバーです。



オブジェクトの部分読み込み



実際のプロジェクトの1つをMongoに転送し始めて、すぐに含まれるネストされたコレクションなしでオブジェクトをロードする必要に直面しました。 問題のドライバーは非常に簡単に動作することに注意してください。 ヘルパーとウィザードのクラスを介して、彼は単純に行を積み重ねて、ネイティブmongo javascriptで作業要求を取得します。 フィールドをロードしないためには、リクエストでfield_nameを指定するだけで十分です:0



db.users.find({}, {thumbnail:0});<br/>







ドライバーではすべてがそれほど明白ではありませんが、少し掘り下げた後、このコードを取得できました。



MongoCollection coll = GetCollection();<br/>

FieldsBuilder fbExclude = Fields.Exclude( new string []{“thumbnail”});<br/>

//can be FindAllAs<TEntity>()

MongoCursor result = coll.FindAll().SetFields(fbExclude);<br/>







カーソル内のすべての結果にはサムネイルフィールドがなく、検証済みであり、うまく機能します。 ロードされていないフィールドはすべて、nullコレクションのデフォルト値で初期化されます。 ここには微妙な点が1つあります。フィールドを読み込まずにこのオブジェクトを書き込むと、データベース内の古いオブジェクトが合法的に粉砕され、そのようなテストは最後のAssertに当てはまります。



public class Data<br/>

{<br/>

[BsonId]<br/>

public ObjectId Id {get;set;}<br/>

public int Area {get;set;}<br/>

}<br/>

Data x = new Data();<br/>

x.Area = 20;<br/>

var db = GetDb();<br/>

var coll = db.GetCollection<Data>( typeof (Data).FullName);<br/>

db.ClearColl<Data>();<br/>

coll.Save(x);<br/>

Data y = coll.FindAllAs<Data>().SetFields(Fields.Exclude( new string []{ "Area" })).FirstOrDefault();<br/>

Assert.AreEqual(0, y.Area);<br/>

coll.Save(y);<br/>

Data z = coll.FindAllAs<Data>().SetFields(

Fields.Exclude( new string [] { "Area" })

).FirstOrDefault();<br/>

//fail of course

Assert.AreEqual(20, z.Area);<br/>







これは検索と変更によって何らかの形で解決されると思いますが、これまでのところそのような必要性はなく、変更する必要があるものはすべて完全にロードされています。



ネストされた配列の要素で選択



私の場合、タスクは1つのヨーロッパの国の郵便番号に基づいて地域を選択することでした。 なぜなら 歴史的な理由により、すべての場合で一般的なロジックが機能しなかったため、次のアルゴリズムに従って地域を決定する必要があります:完全に一致する場合は、見つかった地域を選択し、一致しない場合は最初の2桁を残し、郵便番号の範囲に基づいて地域についての仮定を行います領域、および範囲自体は多くの場合があります。 オブジェクトは次のようになります。



public class HighLevelCodeInterval <br/>

{<br/>

public HighLevelCodeInterval() { }<br/>

<br/>

public HighLevelCodeInterval( int mn, int mx) <br/>

{<br/>

Min = mn; Max = mx;<br/>

}<br/>

public int Min { get; set; }<br/>

public int Max { get; set; }<br/>

}<br/>

public class RegionObject <br/>

{<br/>

public RegionObject() <br/>

{<br/>

PostalCodes = new List< int >();<br/>

}<br/>

<br/>

[BsonId]<br/>

public int Id { get; set; }<br/>

public string Name { get; set; }<br/>

public List<HighLevelCodeInterval> HighLevelCodes { get; set; }<br/>

public List< int > PostalCodes { get; set; }<br/>

}<br/>







次に、特定のコードのクエリは次のようになります。



QueryComplete q = Query.EQ( "PostalCodes" , postCode);<br/>

MongoCollection coll = GetCollection();<br/>

RegionObject result = coll.FindOneAs<RegionObject>();<br/>







意外とシンプルだと思います。 範囲で検索するには、クエリ自体のみを指定します。



int nCodeValue = …;<br/>

Query.And( <br/>

Query.LTE( "HighLevelCodes.Min" , nCodeValue),<br/>

Query.GTE( "HighLevelCodes.Max" , nCodeValue)<br/>

)<br/>







mongoのネストされた配列の検索は非常に価値があることを認めなければなりません。



識別子



ドライバーは2つの組み込み識別子ジェネレーターをサポートします:GuidおよびObjectIdタイプ、つまり これらのタイプのいずれかのプロパティをBsonId属性で装飾するだけで、すべてが自動的に行われます。 しかし、識別子は何でも構いません。整数の識別子は私にとっては問題なく機能しますが、その一意性はmongoに関して外部プログラムによって監視されます。 彼らはまた、ジェネレーター自体を書くことが可能であると言っています:



public class EmployeeIdGenerator : IIdGenerator <br/>

{<br/>

object GenerateId(){ ⋮ }<br/>

bool IsEmpty( object id) { ⋮ }<br/>

}<br/>

public class Employee <br/>

{ <br/>

[BsonId(IdGenerator = typeof (EmployeeIdGenerator)]<br/>

public int Id { get; set; }<br/>

// other fields or properties

}<br/>







私は実際にそれを試していません。



おわりに



ドキュメント指向のデータベースは、すべてのプロジェクトに適したものではありません。 うまく動作しない場合は、DDDだけを適用することはできません。 私のプロジェクトの1つがDDDに完全に適合し、膨大な数のテーブルが消えることを信じられないほどうれしく思います。すべてがうまくいけば、すぐに実際に動作するアプリケーションでMondoDB対MSSQLの精神でパフォーマンステストが行​​われます。



PS:実行された操作の結果としてデータベースに書き込まれたものを確認するのに役立つユーティリティについて言及したいと思います-これはMongo Vueです



All Articles