8

5つのアイテムのコレクション「アイテム」があり、それぞれにIDと配列があります

{ _id: ObjectId("51c21bec162c138d9d0001a7"), 
    tags: [ { name: "a", type: "tag" }, { name: "b", type: "tag" }, { name: "c", type: "note" } ] 
}
{ _id: ObjectId("51c21ca22c69904840000178"), 
    tags: [ { name: "a", type: "tag" }, { name: "d", type: "tag" }, { name: "c", type: "note" } ] 
}
{ _id: ObjectId("51c21cc1478cf6691a0001b4"), 
    tags: [ { name: "d", type: "tag" }, { name: "b", type: "tag" }, { name: "c", type: "note" } ] 
}
{ _id: ObjectId("51c22292162c13b1ff000222"), 
    tags: [ { name: "a", type: "tag" }, { name: "d", type: "tag" }, { name: "e", type: "note" } ] 
}
{ _id: ObjectId("51c222e926d602a57d0001d8"), 
    tags: [ { name: "a", type: "tag" }, { name: "d", type: "note" }, { name: "c", type: "note" } ] 
}

ここでの目標は、タグ「a」および「d」を持つすべてのアイテムを返すことです。タグのタイプは「tag」です。あなたはこれがそれを行うと思ったかもしれません:

find({"tags.name":{"$all":["a","d"]}, "tags.type":'tag'})

は 3 つのドキュメントを返しますが、これは間違っていますが、このクエリは or を実行することを知りました。そこで、'$elemMatch' を使用してこれを実行しようとしましたが、最も直感的な方法だと思いましたが、

find({"tags":{"$elemMatch":{'name':{'$all':["a","d"]}, "type":'tag'}}})

ドキュメントを返しません。

「a」とタグ付けされたアイテムのみが必要な場合は、同じクエリが機能します。

find({"tags":{"$elemMatch":{'name':{'$all':["a"]}, "type":'tag'}}})

おそらく、$all が $eq のようなものにマップされるためです。

最終的に、元の GOAL に対して次のことを行う必要があることがわかりました

find({"tags":{"$all":[{'$elemMatch':{'name':"a", "type":'tag'}}, {'$elemMatch':{'name':"d", "type":'tag'}} ]}})

正しい 2 つのドキュメントを返します。

しかし、この構文はひどいです! 配列 ["a", "d"] を独自にクエリに展開する必要があります。一般的なクエリ エンジンを作成していて、埋め込まれたドキュメントの複数のフィールドが配列であると言いたい場合はどうすればよいでしょうか。各配列から値の特定のサブセットが必要です。

これを行うより良い方法はありますか?より良い構文?

4

2 に答える 2

5

最終的にたどり着いたのが正解です。$elemMatchルールの配列をプログラムで構築することは、改善になる可能性があります。

次のpythonを考えてみましょう:

match_rules = []
for tag in query_tags:
  match_rules.append({
    '$elemMatch': {
      'name': tag
      'type': 'tag'
    }
  })

collection.find({"tags":{"$all": match_rules}})
于 2014-03-04T10:42:28.543 に答える