$(投影)
定义
使用注意事项
$
操作符和 $elemMatch
操作符均会根据某一条件对数组中的第一个匹配元素进行投影。
$
操作符根据查询语句中的某些条件投影一个集合中的每个文档的第一个匹配数组元素。
$elemMatch
投影运算符接受显式条件参数。这允许您根据不在查询中的条件进行投影,或者如果您需要根据数组的嵌入式文档中的多个字段进行投影。有关示例,请参阅数组字段限制。
针对视图的 db.collection.find()
操作不支持 $
投影运算符。
行为
语法
要返回与数组上的指定查询条件匹配的第一个数组元素:
db.collection.find( { <array>: <condition> ... }, { "<array>.$": 1 } ) db.collection.find( { <array.field>: <condition> ...}, { "<array>.$": 1 } )
您可以使用 $
操作符来限制未出现在查询文档中的 <array>
字段。在 MongoDB 的先前版本中,受限制的 <array>
字段必须出现在查询文档中。
db.collection.find( { <someOtherArray>: <condition> ... }, { "<array>.$" : 1 } )
重要
为确保达到预期行为,查询文档和投影文档中使用的数组必须具有相同长度。 如果数组的长度不同,在某些情况下操作可能会出错。
数组字段限制
处理数组投影时,MongoDB 要求满足以下条件:
投影文档中只可以出现一个位置
$
操作符。查询文档中只能出现一个数组字段。查询文档中的额外数组字段可能会导致未定义的行为。
例如,以下投影可能会导致未定义的行为:
db.collection.find( { <array>: <value>, <someOtherArray>: <value2> }, { "<array>.$": 1 } ) 查询文档只应包含一个要应用于数组字段的条件。多个条件可能会在内部相互覆盖,并导致未定义的行为。
要为数组内的多个文档字段指定条件,请使用
$elemMatch
查询运算符。以下查询返回grades
数组中第一个符合以下条件的文档:mean
大于 70 且grade
大于 90。db.students.find( { grades: { $elemMatch: { mean: { $gt: 70 }, grade: { $gt:90 } } } }, { "grades.$": 1 } ) 如需为选择文档和选择这些文档中的字段分别设置条件,则须使用
$elemMatch
运算符。
排序和位置操作符
当 find()
方法包含 sort()
时,find()
方法先应用 sort()
对匹配的文档进行排序,然后应用位置 $
投影运算符。
如果数组字段包含多份具有相同字段名的文档,并且 find()
方法在该重复字段上包含 sort()
,则返回的文档可能无法反映排序顺序,因为排序是在使用 $
投影操作符之前应用于数组元素的。
位置操作符放置限制
$
投影操作符只能出现在字段路径的末尾,例如 "field.$"
或 "fieldA.fieldB.$"
。
例如,以下操作无效:
db.inventory.find( { }, { "instock.$.qty": 1 } )
要解决此问题,请删除字段路径中位于 $
投影运算符之后的部分。
位置操作符和$slice
限制
find
和 findAndModify
投影不能将 $slice
投影表达式纳入 $
投影表达式。
例如,以下操作无效:
db.inventory.find( { "instock.qty": { $gt: 25 } }, { "instock.$": { $slice: 1 } } )
在之前的版本中,MongoDB 返回instock
数组中符合查询条件的第一个元素( instock.$
);即位置投影"instock.$"
优先,而$slice:1
是无需操作。"instock.$": {
$slice: 1 }
不排除任何其他文档字段。
示例
投影数组值
集合 students
包含以下文档:
{ "_id" : 1, "semester" : 1, "grades" : [ 70, 87, 90 ] } { "_id" : 2, "semester" : 1, "grades" : [ 90, 88, 92 ] } { "_id" : 3, "semester" : 1, "grades" : [ 85, 100, 90 ] } { "_id" : 4, "semester" : 2, "grades" : [ 79, 85, 80 ] } { "_id" : 5, "semester" : 2, "grades" : [ 88, 88, 92 ] } { "_id" : 6, "semester" : 2, "grades" : [ 95, 90, 96 ] }
在以下查询中,投影 { "grades.$": 1 }
仅会为 grades
字段返回第一个大于或等于 85
的元素。
db.students.find( { semester: 1, grades: { $gte: 85 } }, { "grades.$": 1 } )
该操作将返回以下文档:
{ "_id" : 1, "grades" : [ 87 ] } { "_id" : 2, "grades" : [ 90 ] } { "_id" : 3, "grades" : [ 85 ] }
虽然数组字段 grades
可能包含多个大于或等于 85
的元素,但$
投影操作符只返回数组中第一个匹配的元素。
项目数组文档
students
集合包含以下文档,其中 grades
字段是文档数组;每个文档包含三个字段名称 grade
、mean
和 std
:
{ "_id" : 7, semester: 3, "grades" : [ { grade: 80, mean: 75, std: 8 }, { grade: 85, mean: 90, std: 5 }, { grade: 90, mean: 85, std: 3 } ] } { "_id" : 8, semester: 3, "grades" : [ { grade: 92, mean: 88, std: 8 }, { grade: 78, mean: 90, std: 5 }, { grade: 88, mean: 85, std: 3 } ] }
在以下查询中,投影 { "grades.$": 1 }
仅返回 grades
字段的 mean
大于 70
的第一个元素:
db.students.find( { "grades.mean": { $gt: 70 } }, { "grades.$": 1 } )
该操作将返回以下文档:
{ "_id" : 7, "grades" : [ { "grade" : 80, "mean" : 75, "std" : 8 } ] } { "_id" : 8, "grades" : [ { "grade" : 92, "mean" : 88, "std" : 8 } ] }