3

トリッキーなmongodbクエリの問題:コレクション「アカウント」があり、(単純化され、実際のデータが非現実的な値に置き換えられた)次のようになります:

{"_id": "<Mongo Binary Data>",
 "Roles": {
     "D7753879C7020F8ECF947122FA211413": {
       "_id": "<Mongo Binary Data>",
       "OrgName": "ACME",
       "Rolename": "Coyote Liaison",
    },

     "CFA7722E6799170706E4C5FFF3F01E63": {
       "_id": "<Mongo Binary Data>",
       "OrgName": "ACME",      
       "Rolename": "MembershipAdmin",
    },

     "C7020F8ECF947122FAGIGHFVFF3F7753": {
       "_id": "<Mongo Binary Data>",
       "OrgName": "Initech",       
       "Rolename": "MembershipAdmin",
    }   
  } 
}

Roles 配列のキーは、役割 ID と組織 ID の組み合わせであり、ハッシュされます。これにより、アカウントにつまり、Initech の MembershipAdmin であるユーザーです。

ここで、任意の組織のロールを持つユーザーをクエリしたいと考えています。これは、疑似 SQL で「Rolename = THISROLENAME であるロール オブジェクトを少なくとも 1 つ持つすべてのアカウントを選択する」と表現できます。つまり、MembershipAdmins であるすべてのユーザーを取得します。

私はこれを試しました:

{
  Roles.Rolename: "MembershipAdmin"
}

この

{
  Roles: {"Rolename": "MembershipAdmin"}
}

この

{
  Roles: {"$elemMatch": {"Rolename": "MembershipAdmin"}}
}

...役に立たず、いくつかの回答などを見てきました。これを回避する唯一の方法は、連想配列キーをサブオブジェクトに押し込むことです。これは、これの主な機能になるため、やりたくありませんデータ構造(アカウントが特定の組織に対して特定の役割を持っているかどうかを確認する)は非常に迅速です。上記の使用例は、管理者ユーザーの責任の一部であるため、非常に高速である必要はありません。そのため、この場合、再帰が過剰なクエリなどは問題ありません。 .

データ構造をリファクタリングせずにこれを機能させる方法を知っている人はいますか? 思いっきりこれで。

どうもありがとう、

G

[編集: 上記の構造はクエリ可能ではありません。学識者の受け入れられた回答を参照してください。ただし、そうしない理由と、それを修正するために適切に行うべきことについての簡単な説明を参照してください。ただし、ハックな回避策で問題ない場合は、データのコピーを BsonArray に保存し、それに対して $elemMatch を使用してクエリを実行できます]

4

3 に答える 3

4

そのスキーマを使用する方法はありません。また、スキーマは最初から非常に実用的でもありません。スキーマを次のように変更する必要があります。

{"_id": "<Mongo Binary Data>",
 "Roles": [
    {
       "hash": "D7753879C7020F8ECF947122FA211413",
       "_id": "<Mongo Binary Data>",
       "OrgName": "ACME",
       "Rolename": "Coyote Liaison",
    },

    {
       "hash": "CFA7722E6799170706E4C5FFF3F01E63",
       "_id": "<Mongo Binary Data>",
       "OrgName": "ACME",      
       "Rolename": "MembershipAdmin",
    },

    {
       "hash": "C7020F8ECF947122FAGIGHFVFF3F7753",
       "_id": "<Mongo Binary Data>",
       "OrgName": "Initech",       
       "Rolename": "MembershipAdmin",
    }   
  ] 
}

ドキュメントのフィールド名として不安定な値を使用することが実用的ではない理由は、ほとんどのクエリが複雑になるためです。唯一の利点は、一部のクエリが少し高速になる可能性があることですが、インデックス作成の問題も引き起こすという事実を考えると、ほとんどの場合、それは悪い考えです.

現在のスキーマを許可するソリューションを探すのではなく、スキーマを上記に変更することを強くお勧めします。

編集: 以下の説明で述べたように、$where 演算子を使用して必要なクエリを作成することは技術的に可能です。他の方法でそれを行うことができない場合は、スキーマの匂いがあり、スケーリングとパフォーマンスの潜在的なボトルネックがあり、ソフトウェアが稼働したときに修正するのが非常に困難であることを意味します. $where を使用しないでください。これまで。

于 2012-08-13T12:12:57.257 に答える
-1

方法は次のとおりです。

db.Accounts.find({
    $where: function () {
        for (var index in this.Roles)
            if (this.Roles[index].Rolename == "THISROLENAME")
                return this;
    }
});

注:配列に埋め込まれた各ドキュメントに独自のキーがある場合、通常の MongoDB クエリが機能しないように設計した理由はわかりませんが、将来的にはその問題が修正されることを願っています。

それまでの間、このソリューションはうまく機能します。私はそれをテストしましたが、かなり速いようです。

于 2014-11-17T07:14:17.647 に答える
-1

[編集]: これは間違っています。ハッシュ構造ではなく配列である場合に機能します。それは、とにかく質問ですでに試されました。

Roles.Rolenameインデックスがあれば使えます。

db.collectionname.ensureIndex({"Roles.Rolename": 1 })

その後、

db.collectionname.find({"Role.Rolename": "MembershipAdmin"})
# returning only the organization field. Not tested though
db.collectionname.find({"Role.Rolename": "MembershipAdmin"},{"Role.Orgname": 1})

MongoDB docsの埋め込みフィールドのインデックス作成に情報があります。

于 2012-08-13T12:10:31.270 に答える