11

Javaには、次のようなオブジェクトがあります。

class MyDoc {
     ObjectId docId;
     Map<String, String> someProps = new HashMap<String,String>(); 
}

これをMongoDBに永続化すると、次のドキュメントが生成されます。

{
    "_id" : ObjectId("4fb538eb5e9e7b17b211d5d3"),
    "someProps" : {
        "4fda4993eb14ea4a4a149c04" : "PROCESSED",
        "4f56a5c4b6f621f092b00525" : "PROCESSED",
        "4fd95a2a0baaefd1837fe504" : "TODO"
    }
}

次のようにクエリする必要があります。

DBObject queryObj =  
new BasicDBObject("someProps.4fda4993eb14ea4a4a149c04","PROCESSED");                        
DBObject explain =  
getCollection().find(queryObj).hint("props_indx").explain();

キーが「4fda4993eb14ea4a4a149c04」で値が「Processed」のsomePropsを持つMyDocドキュメントを見つけてください。

コレクションには何百万ものMyDocドキュメントが保存されているため、someProps埋め込みオブジェクトのキーに効率的なインデックスを付ける必要があります。

マップのキーは事前にわからないため(動的に生成され、固定されたキーのセットではありません)、somePropsキーごとに1つのインデックスを作成できません。(少なくとも、私が間違っていれば私を訂正できるとは思いません)

somePropsで直接インデックスを作成しようとしましたが、クエリに時間がかかりました。

somePropsマップキーのインデックスを作成するにはどうすればよいですか?別のドキュメント構造が必要ですか?

インプロタントノート:

1。同じキーを持つsomePropsの要素は1つだけです。例えば ​​:

{
"_id" : ObjectId("4fb538eb5e9e7b17b211d5d3"),
    "someProps" : {
        "4fda4993eb14ea4a4a149c04" : "PROCESSED",
        "4f56a5c4b6f621f092b00525" : "PROCESSED",
        "4f56a5c4b6f621f092b00525" : "TODO"
    }
}

4f56a5c4b6f621f092b00525がマップ内で2回見つからないため、無効になります(したがって、最初にマップを使用します)

2。また、値を変更するだけで、somePropsを効率的に更新する必要があります(例:「4fda4993eb14ea4a4a149c04」:「PROCESSED」を「4fda4993eb14ea4a4a149c04」:「CANCELLED」に変更)

私のオプションは何ですか?

ありがとう。

4

3 に答える 3

12

プロパティを埋め込みたままにしておきたい場合は、KyleBankeが「MongoDBinAction」で提案した動的属性パターンを使用することもできます。したがって、小道具を独自のコレクションに配置する代わりに、mydocsコレクションを次のように変更します。

{
  "_id" : ObjectId("4fb538eb5e9e7b17b211d5d3"),
  "someProps" : [
      { k: "4fda4993eb14ea4a4a149c04", v: "PROCESSED" },
      { k: "4f56a5c4b6f621f092b00525", v: "PROCESSED" },
      { k: "4fd95a2a0baaefd1837fe504", v : "TODO" }
  ]
}

次に、埋め込まれたドキュメントキーにインデックスを付けます。

db.mydoc.ensureIndex({'someProps.k' :1}, {'someProps.v' :1})

これはSergioが提案したものに非常に近いですが、データは1つのコレクション内の1つのドキュメントのままです。

于 2012-06-28T13:06:35.750 に答える
5

次のようにドキュメントを構造化するのはどうでしょうか。

{
"_id" : ObjectId("4fb538eb5e9e7b17b211d5d3"),
    "someProps" : {
        "PROCESSED":["4fda4993eb14ea4a4a149c04","4f56a5c4b6f621f092b00525"],
        "TODO" : ["4f56a5c4b6f621f092b00526"],
        "CANCELLED" : [ ]
    }
}

そのメリットは次の3つです。

  1. クエリを "someProps.4fda4993eb14ea4a4a149c04","PROCESSED" から "someProps.PROCESSED", "4fda4993eb14ea4a4a149c04" に切り替えることで、オブジェクトが処理されているかどうかを確認できます。

  2. 「someProps.TODO」にインデックスを作成し、「someProps.PROCESSED」に別のインデックスを作成できます(複数の並列配列に複合インデックスを作成することはできませんが、単一のステータスでクエリを実行しているように聞こえますよね?

  3. 次のように、ドキュメントをある状態から別の状態にアトミックに移動できます。

.

db.collection.update({"someProps.PROCESSED": "4fda4993eb14ea4a4a149c04"},
                     {$pull:{"someProps.PROCESSED":"4fda4993eb14ea4a4a149c04"},
                      $push:{"someProps.CANCELLED":"4fda4993eb14ea4a4a149c04"}});
于 2012-06-17T21:30:59.163 に答える
2

これらのプロパティを独自のドキュメントに拡張することをお勧めします。だからあなたの例:

{
    "_id" : ObjectId("4fb538eb5e9e7b17b211d5d3"),
    "someProps" : {
        "4fda4993eb14ea4a4a149c04" : "PROCESSED",
        "4f56a5c4b6f621f092b00525" : "PROCESSED",
        "4fd95a2a0baaefd1837fe504" : "TODO"
    }
}

これになる

{_id: {id1: ObjectId("4fb538eb5e9e7b17b211d5d3"), id2: "4fda4993eb14ea4a4a149c04"}, v: "PROCESSED"}
{_id: {id1: ObjectId("4fb538eb5e9e7b17b211d5d3"), id2: "4f56a5c4b6f621f092b00525"}, v: "PROCESSED"}
{_id: {id1: ObjectId("4fb538eb5e9e7b17b211d5d3"), id2: "4fd95a2a0baaefd1837fe504"}, v: "TODO"}

これid1は、以前の親エンティティ (アプリケーションなど) の ID であり、id2プロパティ ID です。

一意性は、フィールドのプロパティによって強制されます_id。アトミック更新は簡単です。索引付けは簡単です

db.props.ensureIndex({'_id.id2': 1})

唯一の欠点は、ストレージのオーバーヘッドです。

于 2012-06-17T21:46:29.200 に答える