定義
$elemMatch$elemMatch演算子は、クエリ結果の<array>フィールドの内容を、$elemMatch条件に一致する最初の要素のみを含むように制限します。
使用上の考慮事項
返される要素
$演算子と$elemMatch演算子の両方が、条件に基づいて配列から最初に一致する要素を投影します。
$ 演算子は、クエリ ステートメントの条件に基づいて、コレクション内の各ドキュメントから最初に一致する配列要素を投影します。
$elemMatch プロジェクション演算子は明示的な条件引数を受け取ります。これにより、クエリにない条件に基づいて投影したり、配列の埋め込みドキュメント内の複数のフィールドに基づいて投影したりすることができます。例については、「配列フィールドの制限」を参照してください。
フィールドの順序
ドキュメント内のフィールドの順序に関係なく、既存フィールドの $elemMatch プロジェクションでは、他の既存フィールドを包含した後にフィールドが返されます。
たとえば、次のドキュメントを含む players コレクションを考えます。
db.players.insertOne( { name: "player1", games: [ { game: "abc", score: 8 }, { game: "xyz", score: 5 } ], joined: new Date("2020-01-01"), lastLogin: new Date("2020-05-01") } )
次のプロジェクションでは、ドキュメントではjoinedフィールドとlastLoginフィールドの前に フィールドがリストされているにもかかわらず、プロジェクションに含まれる他の既存フィールドの後にgamesフィールドが返されます。
db.players.find( {}, { games: { $elemMatch: { score: { $gt: 5 } } }, joined: 1, lastLogin: 1 } )
つまり、この操作は次のドキュメントを返します。
{ "_id" : ObjectId("5edef64a1c099fff6b033977"), "joined" : ISODate("2020-01-01T00:00:00Z"), "lastLogin" : ISODate("2020-05-01T00:00:00Z"), "games" : [ { "game" : "abc", "score" : 8 } ] }
制限事項
ビューにおける
db.collection.find()操作は$elemMatchプロジェクション演算子をサポートしていません。$textクエリ式は$elemMatchで指定できません。
例
$elemMatchプロジェクション演算子の例では、次のドキュメントを含むコレクションschoolsを前提としています。
{ _id: 1, zipcode: "63109", students: [ { name: "john", school: 102, age: 10 }, { name: "jess", school: 102, age: 11 }, { name: "jeff", school: 108, age: 15 } ] }, { _id: 2, zipcode: "63110", students: [ { name: "ajax", school: 100, age: 7 }, { name: "achilles", school: 100, age: 8 }, ], athletics: [ "swimming", "basketball", "football" ] }, { _id: 3, zipcode: "63109", students: [ { name: "ajax", school: 100, age: 7 }, { name: "achilles", school: 100, age: 8 }, ], athletics: [ "baseball", "basketball", "soccer" ] }, { _id: 4, zipcode: "63109", students: [ { name: "barney", school: 102, age: 7 }, { name: "ruth", school: 102, age: 16 }, ] }
次の C# クラスを使用して、これらのドキュメントをモデル化できます。
public class School { public string Id { get; set; } [] public string ZipCode { get; set; } public Student[] Students { get; set; } public string[] Athletics { get; set; } }
public class Student { public string Id { get; set; } public string Name { get; set; } public int School { get; set; } public int Age { get; set; } }
郵便番号検索
次の find() 操作は、 zipcode フィールドの値が "63109" であるすべてのドキュメントを照会します。$elemMatch プロジェクションは、school フィールドの値が 102 である students 配列の最初に一致する要素のみを返します。
db.schools.find( { zipcode: "63109" }, { students: { $elemMatch: { school: 102 } } } )
.NET/ C#ドライバーを使用して $elemMatchプロジェクションを実行するには、プロジェクションビルダで ElemMatch() メソッドを呼び出します。プロジェクトを行う配列フィールドの名前と、配列要素に適用するフィルターを渡します。
次のコード例では、Zipcode フィールドの値が "63109" であるすべてのドキュメントを検索します。各一致ドキュメントに対して、プロジェクションは以下のフィールドを返します。
Idネストされた
Schoolフィールドの値が102である値を持つStudents配列の最初の要素
var results = schoolsCollection .Find(s => s.ZipCode == "63109") .Project(Builders<School>.Projection.ElemMatch( field: school => school.Students, filter: student => student.School == 102 ) ).ToList();
この操作は、zipcode 値が "63109" である次のドキュメントを返し、$elemMatch を使用して students 配列を表示します。
{ "_id" : 1, "students" : [ { "name" : "john", "school" : 102, "age" : 10 } ] } { "_id" : 3 } { "_id" : 4, "students" : [ { "name" : "barney", "school" : 102, "age" : 7 } ] }
_idが1に等しいドキュメントの場合、students配列には、schoolフィールドが102に等しい複数の要素が含まれています。ただし、$elemMatchプロジェクションは配列から最初に一致する要素のみを返します。_idが3に等しいドキュメントでは、students配列のどの要素も$elemMatch条件に一致しなかったため、結果にstudentsフィールドは含まれません。
$elemMatch 複数のフィールド付き
$elemMatchプロジェクションでは、複数のフィールドに対して条件を指定できます。
次の find() 操作は、 zipcode フィールドの値が "63109" であるすべてのドキュメントを照会します。投影には、 school フィールドの値が 102 で、age フィールドの値が 10 より大きい students 配列の最初の一致する要素が含まれます。
db.schools.find( { zipcode: "63109" }, { students: { $elemMatch: { school: 102, age: { $gt: 10} } } } )
次のコード例では、Zipcode フィールドの値が "63109" であるすべてのドキュメントを検索します。各一致ドキュメントに対して、プロジェクションは以下のフィールドを返します。
IdStudents配列の最初の要素で、ネストされたSchoolフィールドの値が102であり、Ageフィールドの値が10より大きい
var results = schoolsCollection .Find(s => s.ZipCode == "63109") .Project(Builders<School>.Projection.ElemMatch( field: school => school.Students, filter: student => (student.School == 102) && (student.Age > 10) ) ).ToList();
この操作では、次のように、zipcode の値が "63109" である 3 つのドキュメントが返されます。
{ "_id" : 1, "students" : [ { "name" : "jess", "school" : 102, "age" : 11 } ] } { "_id" : 3 } { "_id" : 4, "students" : [ { "name" : "ruth", "school" : 102, "age" : 16 } ] }
が_id 3studentsに等しいドキュメントには、 条件に一致する配列要素がなかったため、$elemMatch フィールドは含まれていません。
$elemMatchへの引数は、 $elemMatchがプロジェクションしている配列の要素と一致します。 フィールド名で等価性を$elemMatchに指定すると、配列内のオブジェクトの一致が試行されます。 たとえば、 $elemMatchは、プロジェクションの次の配列内で、スカラー値ではなくオブジェクトを照合しようとします。
db.schools.find( { zipcode: "63109" }, { athletics: { $elemMatch: { athletics: "basketball" } } })
var results = schoolsCollection .Find(s => s.ZipCode == "63109") .Project(Builders<School>.Projection.ElemMatch( "athletics", Builders<School>.Filter.Eq("athletics", "basketball")) ).ToList();
上記の例では、zipcode 値が "63109" であるドキュメントが返されますが、プロジェクション操作では一致する要素が見つからなかったため、これらのドキュメントには _idフィールドのみが含まれます。
スカラー値をマッチングするには、等価演算子と一致させるスカラー値をマッチングします( {$eq: <scalar value>} )。 たとえば、次のfind()操作は、 zipcodeフィールドの値が"63109"であるすべてのドキュメントを照会します。 投影には、値がbasketballであるathletics配列の一致する要素が含まれます。
db.schools.find( { zipcode: "63109" }, { athletics: { $elemMatch: { $eq: "basketball" } } })
.NET/C# ドライバーを使用して配列内のスカラー値に対して $elemMatch 操作を実行するには、プロジェクション ビルダーの ElemMatch() メソッドを呼び出します。プロジェクトする配列フィールドの名前と、フィールド "$eq" の等価フィルター、および比較対象の値を渡します。
var results = schoolsCollection .Find(s => s.ZipCode == "63109") .Project(Builders<School>.Projection.ElemMatch( field: "athletics", filter: Builders<School>.Filter.Eq("$eq", "basketball")) ).ToList();
この操作では、zipcode の値が "63109" である 3 つのドキュメントが返されます。返されるドキュメントには、_id フィールドと athletics 配列の一致する要素(存在する場合)が含まれます。
[ { _id: 1 }, { _id: 3, athletics: [ 'basketball' ] }, { _id: 4 } ]
_idが3に等しいドキュメントが、 $elemMatch条件に一致した唯一のドキュメントです。
Tip
$ (projection) 演算子