下面的方法也能从一个集合中读取文档:
· db.collection.findOne
· 在聚集管道中,$match 管道支持MongoDB 查询。
1读取隔离
3.2版本新增
为了读取副本集和副本集分片,读关注(read concern)允许客户端选则读隔离级别。
2投影字段以返回查询结果
默认返回文档中所有字段。为了限制返回结果的数据量,可以在查询操作中使用投影器文档。
投影器文档
投影器文档限制了查询操作返回所有匹配到的文档的字段。投影器文档指定了返回结果中包含或排除哪些字段,其格式为:{ field1: <value>, field2: <value> ... }
<value>可以是下面的任何值:
- 1或true表示字段被包含在返回的结果文档中。
- 0或false表示字段不包含在返回的结果文档中。
- 当<value>为表达式时,要使用投影器操作符。
注:
对于_id字段,为使其包含在返回结果中,不用明确指定“_id:1”。db.collection.find() 方法返回结果中总是包含_id字段,除非指定“ _id: 0 ”。
投影器不能同时使用包含规范和排除规范,除对_id做排除以外。在明确指定包含规范的投影器中,仅可对_id字段指定排除规范。
示例集合
在mongo shell中,使用db.collection.find()来检索本页的集合,如果一个游标没有赋给一个var变量,那么游标自动迭代20次以打印查询结果中的前20个文档。
在mongo shell中执行下面的语句来填充users 集合。
注:
如果在集合users 中,已有文档的_id字段值和待插入文档的_id字段值相同,那么要先将集合users删除。
db.users.insertMany( [ { _id: 1, name: "sue", age: 19, type: 1, status: "P", favorites: { artist: "Picasso", food: "pizza" }, finished: [ 17, 3 ], badges: [ "blue", "black" ], points: [ { points: 85, bonus: 20 }, { points: 85, bonus: 10 } ] }, { _id: 2, name: "bob", age: 42, type: 1, status: "A", favorites: { artist: "Miro", food: "meringue" }, finished: [ 11, 25 ], badges: [ "green" ], points: [ { points: 85, bonus: 20 }, { points: 64, bonus: 12 } ] }, { _id: 3, name: "ahn", age: 22, type: 2, status: "A", favorites: { artist: "Cassatt", food: "cake" }, finished: [ 6 ], badges: [ "blue", "red" ], points: [ { points: 81, bonus: 8 }, { points: 55, bonus: 20 } ] }, { _id: 4, name: "xi", age: 34, type: 2, status: "D", favorites: { artist: "Chagall", food: "chocolate" }, finished: [ 5, 11 ], badges: [ "red", "black" ], points: [ { points: 53, bonus: 15 }, { points: 51, bonus: 15 } ] }, { _id: 5, name: "xyz", age: 23, type: 2, status: "D", favorites: { artist: "Noguchi", food: "nougat" }, finished: [ 14, 6 ], badges: [ "orange" ], points: [ { points: 71, bonus: 20 } ] }, { _id: 6, name: "abc", age: 43, type: 1, status: "A", favorites: { food: "pizza", artist: "Picasso" }, finished: [ 18, 12 ], badges: [ "black", "blue" ], points: [ { points: 78, bonus: 8 }, { points: 57, bonus: 7 } ] } ] )
返回匹配到的全部字段
使用db.collection.find()方法检索而不使用投影器,将返回文档的全部字段。
例如,从users 集合中检索字段status 的值为“A”的文档。
db.users.find( { status: "A" } )
查询结果:
{ "_id" : 2, "name" : "bob", "age" : 42, "type" : 1, "status" : "A", "favorites" : { "artist" : "Miro", "food" : "meringue" }, "finished" : [ 11, 25 ], "badges" : [ "green" ], "points" : [ { "points" : 85, "bonus" : 20 }, { "points" : 64, "bonus" : 12 } ]} { "_id" : 3, "name" : "ahn", "age" : 22, "type" : 2, "status" : "A", "favorites" : { "artist" : "Cassatt", "food" : "cake" }, "finished" : [ 6 ], "badges" : [ "blue", "red" ], "points" : [ { "points" : 81, "bonus" : 8 }, { "points" : 55, "bonus" : 20 } ]} { "_id" : 6, "name" : "abc", "age" : 43, "type" : 1, "status" : "A", "favorites" : { "food" : "pizza", "artist" : "Picasso" }, "finished" : [ 18, 12 ], "badges" : [ "black", "blue" ], "points" : [ { "points" : 78, "bonus" : 8 }, { "points" : 57, "bonus" : 7 } ]}
只返回指定字段和_id字段
例如,结果集中只包含name, status和_id字段
db.users.find( { status: "A" }, { name: 1, status: 1 } )
查询结果为:
{ "_id" : 2, "name" : "bob", "status" : "A" } { "_id" : 3, "name" : "ahn", "status" : "A" } { "_id" : 6, "name" : "abc", "status" : "A" }
只返回指定字段
db.users.find( { status: "A" }, { name: 1, status: 1, _id: 0 } )
查询结果为:
{ "name" : "bob", "status" : "A" } { "name" : "ahn", "status" : "A" } { "name" : "abc", "status" : "A" }
排除某些字段
db.users.find( { status: "A" }, { favorites: 0, points: 0 } )
查询结果为:
{ "_id" : 2, "name" : "bob", "age" : 42, "type" : 1, "status" : "A", "finished" : [ 11, 25 ], "badges" : [ "green" ]}{ "_id" : 3, "name" : "ahn", "age" : 22, "type" : 2, "status" : "A", "finished" : [ 6 ], "badges" : [ "blue", "red" ]} { "_id" : 6, "name" : "abc", "age" : 43, "type" : 1, "status" : "A", "finished" : [ 18, 12 ], "badges" : [ "black", "blue" ]}
返回嵌入式文档中指定字段
使用圆点操作符指定嵌入式文档中的字段。
例如,设定投影器,返回_id 字段, name字段, status字段, 和嵌入式文档favorites 中的food 字段,food字段被包含在匹配到的文档的字段favorites 中。
db.users.find( { status: "A" }, { name: 1, status: 1, "favorites.food": 1 } )
查询结果为:
{ "_id" : 2, "name" : "bob", "status" : "A", "favorites" : { "food" : "meringue" } } { "_id" : 3, "name" : "ahn", "status" : "A", "favorites" : { "food" : "cake" } } { "_id" : 6, "name" : "abc", "status" : "A", "favorites" : { "food" : "pizza" } }
排除嵌入式文档中的指定字段
使用圆点操作符将嵌入式文档中的字段值设置为0。
例如,排除嵌入式文档favorites中的food字段,其他字段都返回
db.users.find( { status: "A" }, { "favorites.food": 0 } )
查询结果为:
{ "_id" : 2, "name" : "bob", "age" : 42, "type" : 1, "status" : "A", "favorites" : { "artist" : "Miro" }, "finished" : [ 11, 25 ], "badges" : [ "green" ], "points" : [ { "points" : 85, "bonus" : 20 }, { "points" : 64, "bonus" : 12 } ] } { "_id" : 3, "name" : "ahn", "age" : 22, "type" : 2, "status" : "A", "favorites" : { "artist" : "Cassatt" }, "finished" : [ 6 ], "badges" : [ "blue", "red" ], "points" : [ { "points" : 81, "bonus" : 8 }, { "points" : 55, "bonus" : 20 } ] } { "_id" : 6, "name" : "abc", "age" : 43, "type" : 1, "status" : "A", "favorites" : { "artist" : "Picasso" }, "finished" : [ 18, 12 ], "badges" : [ "black", "blue" ], "points" : [ { "points" : 78, "bonus" : 8 }, { "points" : 57, "bonus" : 7 } ] }
投射器作用于数组中的嵌入式文档
使用圆点操作符投射数组中嵌入式文档的指定字段。
例如,指定投射器,返回name字段 、status 字段和bonus 字段;_id 字段默认返回。
db.users.find( { status: "A" }, { name: 1, status: 1, "points.bonus": 1 } )
查询结果:
{ "_id" : 2, "name" : "bob", "status" : "A", "points" : [ { "bonus" : 20 }, { "bonus" : 12 } ] } { "_id" : 3, "name" : "ahn", "status" : "A", "points" : [ { "bonus" : 8 }, { "bonus" : 20 } ] } { "_id" : 6, "name" : "abc", "status" : "A", "points" : [ { "bonus" : 8 }, { "bonus" : 7 } ] }
在返回的数组中投射指定的数组元素
对于包含数组的字段,MongoDB提供了下面的投影器操作符:$elemMatch, $slice, 和$.
例如,使用 $slice投影操作符来返回scores 数组中最后一个元素。
db.users.find( { status: "A" }, { name: 1, status: 1, points: { $slice: -1 } } )
查询结果为:
{ "_id" : 2, "name" : "bob", "status" : "A", "points" : [ { "points" : 64, "bonus" : 12 } ] } { "_id" : 3, "name" : "ahn", "status" : "A", "points" : [ { "points" : 55, "bonus" : 20 } ] } { "_id" : 6, "name" : "abc", "status" : "A", "points" : [ { "points" : 57, "bonus" : 7 } ] }
$elemMatch, $slice, 和$是投射指定元素(多个)且使其包含在返回结果中的仅有的方式。例如,不能使用数组索引投射任何元素,投影器{ "ratings.0": 1 },不会投射数组中的第一个元素。
3查询null或缺失的字段
在MongoDB 中,不同的操作符对待null值是不同的。
本页中的例子在mongo shell中执行db.collection.find()方法。为了填充集合users,在mongo shell中执行:
db.users.insert( [ { "_id" : 900, "name" : null }, { "_id" : 901 } ] )
相等过滤器
查询匹配文档{ name : null }检索出这样的文档:文档包含值为null的name字段,或者文档不包含name字段。
给出如下查询:
db.users.find( { name: null } )
查询返回结果为:
{ "_id" : 900, "name" : null } { "_id" : 901 }
如果索引是稀疏的,那么只会匹配null值而不是缺失的字段。
2.6版本中的变更:如果使用稀疏索引导致不完整的结果,MongoDB 将不会使用索引,除非使用hint()指定索引。
类型检测
使用{ name : { $type: 10 } }匹配出name 字段为null的文档。例如name 字段值为Null(BSON类型)。
db.users.find( { name : { $type: 10 } } )
查询结果为:
{ "_id" : 900, "name" : null }
存在检测
使用{ name : { $exists: false } }匹配出不包含某一字段的文档:
db.users.find( { name : { $exists: false } } )
查询结果为:
{ "_id" : 901 }
3.1在mongo shell中迭代游标
db.collection.find() 方法返回游标,为了使用文档,你需要迭代游标。然而,如果返回的游标没有赋给var类型的变量,那么游标会自动迭代20次以打印结果集中前20个文档。
下面的例子描述了手动迭代游标来使用文档或迭代器索引的方式。
手动迭代游标
在mongo shell,当你将由 find()方法返回的游标赋给var类型变量时,游标不会迭代。
你可以在mongo shell中调用游标变量,迭代20次并打印匹配文档,例子如下:
var myCursor = db.users.find( { type: 2 } ); myCursor
你可以使用游标方法next() 来使用文档,例子如下:
var myCursor = db.users.find( { type: 2 } ); while (myCursor.hasNext()) { print(tojson(myCursor.next())); }
作为一种替代的打印方式,考虑使用printjson()这一帮助方法来替代print(tojson()):
var myCursor = db.users.find( { type: 2 } ); while (myCursor.hasNext()) { printjson(myCursor.next()); }
你可以使用游标方法forEach()来迭代游标并使用文档,例子如下:
var myCursor = db.users.find( { type: 2 } ); myCursor.forEach(printjson);
迭代器索引
在mongo shell,你可以使用toArray()方法来迭代游标并返回数组中的文档,例子如下:
var myCursor = db.inventory.find( { type: 2 } ); var documentArray = myCursor.toArray(); var myDocument = documentArray[3];
toArray() 方法将游标返回的所有文档都加载到内存中,它会耗尽游标。
另外,一些驱动提供了通过使用游标索引来获得文档的方法(例如,cursor[index])。先调用toArray()方法,然后使用结果集索引,这是一种便捷的方式。
考虑如下的例子:
var myCursor = db.users.find( { type: 2 } ); var myDocument = myCursor[1]; 同myCursor[1] 等价的方式为: myCursor.toArray() [1];
游标行为
关闭无效的游标
默认地,游标的不活跃时期超过十分钟时或者客户端耗尽游标,服务器会自动关闭游标。为在mongo shell中重设置这一行为,可以使用cursor.noCursorTimeout()方法:
var myCursor = db.users.find().noCursorTimeout();
设置了noCursorTimeout 选项以后,必须使用cursor.close() 方法手动关闭游标,或者通过耗尽游标结果的方式关闭游标。
游标隔离
当使用游标获得文档的同时,其他的查询操作可能正在执行。对于MMAPv1 存储引擎,对一个文档的交替写操作,如果文档已经改变了,可能导致游标返回同一文档两次。为了控制这种情况,请参考snapshot mode。
游标批处理
MongoDB 成批地返回查询结果。批大小不会超过BSON文档的最大值。对于大多数查询来说,第一批返回101个文档,或者超过1MB的文档,随后的批大小为4MB,为了重置批大小,可以使用batchSize() 和limit()方法。
没有索引的情况下,如果查询包含排序操作,服务器要将所有的文档加载到内存中以执行排序。
当你使用游标迭代并且达到了已返回那批的末尾时,如果还有更多的数据,cursor.next() 方法将会执行获取更多操作来检索下一批。当你迭代游标时,为了查看有多少文档在某一批中,你可以使用objsLeftInBatch()方法,例如:
var myCursor = db.inventory.find(); var myFirstDocument = myCursor.hasNext() ? myCursor.next() : null; myCursor.objsLeftInBatch();
游标信息
db.serverStatus() 方法返回的文档中包含metrics 字段,metrics 字段包含具有如下信息的metrics.cursor 字段:
· 从服务器最近一次重启到当期时间的超时游标数量。
· 设置DBQuery.Option.noTimeout选项的已打开游标数量,设置DBQuery.Option.noTimeout可防止一段不活跃期后游标超时。
· 被“定住”的已打开游标。
· 已打开游标的总数。
如下的例子中,调用db.serverStatus()方法,使用返回结果中的字段metrics 和metrics 中的字段cursor:
db.serverStatus().metrics.cursor
执行结果为:
{ "timedOut" : <number> "open" : { "noTimeout" : <number>, "pinned" : <number>, "total" : <number> } }
注
本文内容主要译自官方文档