一、最直接的匹配查询和比较操作符
1.1 开始读取文档
db.collection.find()
db.<collection>.find(<query>,<projection>)
<query>文档定义了读取操作时筛选文档的条件
<projection>文档定义了对读取结果进行的投射操作
- 读取全部文档
既不筛选,也不投射
> db.accounts.find()
{ "_id" : "account1", "name" : "alice", "balance" : 100 }
{ "_id" : ObjectId("63bd080fef3b5e682a151ff8"), "name" : "bob", "balance" : 50 }
{ "_id" : ObjectId("63bd1a23ef3b5e682a151ff9"), "name" : "charlie", "balance" : 500 }
{ "_id" : ObjectId("63bd1a23ef3b5e682a151ffa"), "name" : "david", "balance" : 200 }
{ "_id" : ObjectId("63bd1c91ef3b5e682a151ffc"), "name" : "david", "balance" : 20 }
{ "_id" : ObjectId("63bd203cef3b5e682a151ffd"), "name" : "george", "balance" : 1000 }
# 让格式更好看点用pretty()
> db.accounts.find().pretty()
{ "_id" : "account1", "name" : "alice", "balance" : 100 }
{
"_id" : ObjectId("63bd080fef3b5e682a151ff8"),
"name" : "bob",
"balance" : 50
}
{
"_id" : ObjectId("63bd1a23ef3b5e682a151ff9"),
"name" : "charlie",
"balance" : 500
}
{
"_id" : ObjectId("63bd1a23ef3b5e682a151ffa"),
"name" : "david",
"balance" : 200
}
{
"_id" : ObjectId("63bd1c91ef3b5e682a151ffc"),
"name" : "david",
"balance" : 20
}
{
"_id" : ObjectId("63bd203cef3b5e682a151ffd"),
"name" : "george",
"balance" : 1000
}
1.2 筛选文档-匹配查询
- 读取alice的银行账户
> db.accounts.find({name:"alice"})
{ "_id" : "account1", "name" : "alice", "balance" : 100 }
- 读取alice的余额为100元的银行账户文档
> db.accounts.find({name:"alice",balance:100})
{ "_id" : "account1", "name" : "alice", "balance" : 100 }
- 读取alice的余额为200元的银行账户文档
> db.accounts.find({name:"alice",balance:200})
>
- 读取银行账户类型为储蓄账户的文档(查找复合主键的内部对象)
> db.accounts.find({"_id.type":"savings"})
{ "_id" : { "accountNo" : "001", "type" : "savings" }, "name" : "irene", "balance" : 80 }
{ "_id" : { "type" : "savings", "accountNo" : "001" }, "name" : "irene", "balance" : 80 }
1.3 筛选文档-比较操作符
{<field>:{$<operator>:<value>}}
$eq 匹配字段值 相等 的文档
$ne 匹配字段值 不等 的文档
$gt 匹配字段值 大于 查询值的文档
$gte 匹配字段值 大于或等于 查询值的文档
$lt 匹配字段值 小于 查询值的文档
$lte 匹配字段值 小于或等于 查询值的文档
{ field : { $in: [ <value1>, <value2>...<valueN> ] } }
$in 匹配字段值与任一查询值相等的文档
{ field : { $nin: [ <value1>, <value2>...<valueN> ] } }
$nin 匹配字段值与任何查询值都不等的文档
- 读取
属于alice的银行账户文档
> db.accounts.find({name:{$eq:"alice"}})
{ "_id" : "account1", "name" : "alice", "balance" : 100 }
上面筛选条件和之前使用的匹配查询有相同的效果db.accounts.find({name:"alice"})
- 读取
不属于alice的文档
> db.accounts.find({name:{$ne:"alice"}})
{ "_id" : ObjectId("63bd080fef3b5e682a151ff8"), "name" : "bob", "balance" : 50 }
{ "_id" : ObjectId("63bd1a23ef3b5e682a151ff9"), "name" : "charlie", "balance" : 500 }
{ "_id" : ObjectId("63bd1a23ef3b5e682a151ffa"), "name" : "david", "balance" : 200 }
{ "_id" : ObjectId("63bd1c91ef3b5e682a151ffc"), "name" : "david", "balance" : 20 }
{ "_id" : ObjectId("63bd203cef3b5e682a151ffd"), "name" : "george", "balance" : 1000 }
{ "_id" : { "accountNo" : "001", "type" : "savings" }, "name" : "irene", "balance" : 80 }
{ "_id" : { "type" : "savings", "accountNo" : "001" }, "name" : "irene", "balance" : 80 }
- 读取余额
不等于100元的银行账户文档
> db.accounts.find({balance:{$ne:100}})
{ "_id" : ObjectId("63bd080fef3b5e682a151ff8"), "name" : "bob", "balance" : 50 }
{ "_id" : ObjectId("63bd1a23ef3b5e682a151ff9"), "name" : "charlie", "balance" : 500 }
{ "_id" : ObjectId("63bd1a23ef3b5e682a151ffa"), "name" : "david", "balance" : 200 }
{ "_id" : ObjectId("63bd1c91ef3b5e682a151ffc"), "name" : "david", "balance" : 20 }
{ "_id" : ObjectId("63bd203cef3b5e682a151ffd"), "name" : "george", "balance" : 1000 }
{ "_id" : { "accountNo" : "001", "type" : "savings" }, "name" : "irene", "balance" : 80 }
{ "_id" : { "type" : "savings", "accountNo" : "001" }, "name" : "irene", "balance" : 80 }
$ne 也会筛选出并不包含查询字段的文档
- 读取银行账户类型
不是储蓄账户的文档
> db.accounts.find({"_id.type":{$ne:"savings"}})
{ "_id" : "account1", "name" : "alice", "balance" : 100 }
{ "_id" : ObjectId("63bd080fef3b5e682a151ff8"), "name" : "bob", "balance" : 50 }
{ "_id" : ObjectId("63bd1a23ef3b5e682a151ff9"), "name" : "charlie", "balance" : 500 }
{ "_id" : ObjectId("63bd1a23ef3b5e682a151ffa"), "name" : "david", "balance" : 200 }
{ "_id" : ObjectId("63bd1c91ef3b5e682a151ffc"), "name" : "david", "balance" : 20 }
{ "_id" : ObjectId("63bd203cef3b5e682a151ffd"), "name" : "george", "balance" : 1000 }
以上结果并不包含type字段但是依旧会被查询出来
- 读取余额
大于500元的银行账户文档
> db.accounts.find({balance:{$gt:500}})
{ "_id" : ObjectId("63bd203cef3b5e682a151ffd"), "name" : "george", "balance" : 1000 }
- 读取用户名字排在fred
之前的银行账户文档(按照字母排序)
> db.accounts.find({name:{$lt:"fred"}})
{ "_id" : "account1", "name" : "alice", "balance" : 100 }
{ "_id" : ObjectId("63bd080fef3b5e682a151ff8"), "name" : "bob", "balance" : 50 }
{ "_id" : ObjectId("63bd1a23ef3b5e682a151ff9"), "name" : "charlie", "balance" : 500 }
{ "_id" : ObjectId("63bd1a23ef3b5e682a151ffa"), "name" : "david", "balance" : 200 }
{ "_id" : ObjectId("63bd1c91ef3b5e682a151ffc"), "name" : "david", "balance" : 20 }
- 读取alice和charlie的银行账户文档
> db.accounts.find({name:{$in:["alice",'charlie']}})
{ "_id" : "account1", "name" : "alice", "balance" : 100 }
{ "_id" : ObjectId("63bd1a23ef3b5e682a151ff9"), "name" : "charlie", "balance" : 500 }
- 读取除了alice和charlie以外的其他用户的银行账户文档
> db.accounts.find({name:{$nin:["alice",'charlie']}})
{ "_id" : ObjectId("63bd080fef3b5e682a151ff8"), "name" : "bob", "balance" : 50 }
{ "_id" : ObjectId("63bd1a23ef3b5e682a151ffa"), "name" : "david", "balance" : 200 }
{ "_id" : ObjectId("63bd1c91ef3b5e682a151ffc"), "name" : "david", "balance" : 20 }
{ "_id" : ObjectId("63bd203cef3b5e682a151ffd"), "name" : "george", "balance" : 1000 }
{ "_id" : { "accountNo" : "001", "type" : "savings" }, "name" : "irene", "balance" : 80 }
{ "_id" : { "type" : "savings", "accountNo" : "001" }, "name" : "irene", "balance" : 80 }
$nin也会筛选出并不包含该查询字段的文档
- 读取账户类型不是储蓄账户的文档
> db.accounts.find({"_id.type":{$nin:["savings"]}})
{ "_id" : "account1", "name" : "alice", "balance" : 100 }
{ "_id" : ObjectId("63bd080fef3b5e682a151ff8"), "name" : "bob", "balance" : 50 }
{ "_id" : ObjectId("63bd1a23ef3b5e682a151ff9"), "name" : "charlie", "balance" : 500 }
{ "_id" : ObjectId("63bd1a23ef3b5e682a151ffa"), "name" : "david", "balance" : 200 }
{ "_id" : ObjectId("63bd1c91ef3b5e682a151ffc"), "name" : "david", "balance" : 20 }
{ "_id" : ObjectId("63bd203cef3b5e682a151ffd"), "name" : "george", "balance" : 1000 }
二、逻辑操作符和字段操作符
# 逻辑操作符
$not 匹配筛选条件不成立的文档
$and 匹配多个筛选条件全部成立的文档
$or 匹配至少一个筛选条件成立的文档
$nor 匹配多个筛选条件全部不成立的文档
2.1 逻辑操作符-$not
{filed: { $not: { <operator-expression>}}}
- 读取余额小于500的银行账户文档
> db.accounts.find({balance:{$not:{$lt:500}}})
{ "_id" : ObjectId("63bd1a23ef3b5e682a151ff9"), "name" : "charlie", "balance" : 500 }
{ "_id" : ObjectId("63bd203cef3b5e682a151ffd"), "name" : "george", "balance" : 1000 }
$not也会筛选出并不包含该查询字段的文档
- 读取账户类型不是储蓄账户的银行账户文档
> db.accounts.find({"_id.type":{$not:{"$eq":"savings"}}})
{ "_id" : "account1", "name" : "alice", "balance" : 100 }
{ "_id" : ObjectId("63bd080fef3b5e682a151ff8"), "name" : "bob", "balance" : 50 }
{ "_id" : ObjectId("63bd1a23ef3b5e682a151ff9"), "name" : "charlie", "balance" : 500 }
{ "_id" : ObjectId("63bd1a23ef3b5e682a151ffa"), "name" : "david", "balance" : 200 }
{ "_id" : ObjectId("63bd1c91ef3b5e682a151ffc"), "name" : "david", "balance" : 20 }
{ "_id" : ObjectId("63bd203cef3b5e682a151ffd"), "name" : "george", "balance" : 1000 }
2.2逻辑操作符-$and
{$and: [ {<expression>}, {<expression2>},..., {<expressionN>} ] }
- 读取余额大于100 并且 用户姓名排在fred之后的银行账户文档
db.accounts.find(
{
$and: [
{ balance: {$gt: 100}},
{ name: {$gt: "fred"}}
]
}
)
{ "_id" : ObjectId("63bd203cef3b5e682a151ffd"), "name" : "george", "balance" : 1000 }
{ "_id" : ObjectId("63be621def3b5e682a152000"), "name" : "george", "balance" : 1000 }
当筛选条件应用在不同字段上时,可以省略$and操作符
db.accounts.find(
{
balance: {$gt: 100},
name: {$gt: "fred"}
}
)
{ "_id" : ObjectId("63bd203cef3b5e682a151ffd"), "name" : "george", "balance" : 1000 }
{ "_id" : ObjectId("63be621def3b5e682a152000"), "name" : "george", "balance" : 1000 }
当筛选条件应用在同一个字段上时,也可以简化命令
- 读取余额大于100并且小于500的银行账户文档
> db.accounts.find( { balance: {$gt: 100, $lt: 500}})
{ "_id" : ObjectId("63bd1a23ef3b5e682a151ffa"), "name" : "david", "balance" : 200 }
2.3 逻辑操作符-$or
{ $or: [ {<expression1>}, {<expression2>}, ... , {<expressionN>} ] }
- 读取属于alice或者charlie的银行账户文档
db.accounts.find( {
$or: [
{ name: { $eq: "alice"} },
{ name: { $eq: "charlie"}}
]
})
{ "_id" : "account1", "name" : "alice", "balance" : 100 }
{ "_id" : ObjectId("63bd1a23ef3b5e682a151ff9"), "name" : "charlie", "balance" : 500 }
当所有筛选条件使用的都是or和in的效果是相同的db.accounts.find( {name: {in:["alice","charlie"]}})
- 读取余额小于100 或者大于500的银行账户文档
db.accounts.find({
$or : [
{balance: {$lt: 100}},
{balance: {$gt: 500}}
]
})
{ "_id" : ObjectId("63bd080fef3b5e682a151ff8"), "name" : "bob", "balance" : 50 }
{ "_id" : ObjectId("63bd1c91ef3b5e682a151ffc"), "name" : "david", "balance" : 20 }
{ "_id" : ObjectId("63bd203cef3b5e682a151ffd"), "name" : "george", "balance" : 1000 }
{ "_id" : { "accountNo" : "001", "type" : "savings" }, "name" : "irene", "balance" : 80 }
{ "_id" : { "type" : "savings", "accountNo" : "001" }, "name" : "irene", "balance" : 80 }
{ "_id" : ObjectId("63be621def3b5e682a152000"), "name" : "george", "balance" : 1000 }
2.4 逻辑操作符-$nor
{ $nor: [ {<expression1>}, {<expression2>}, ..., {<expressionN>}]}
- 读取不属于alice和charlie且余额不小于100的银行账户文档
db.accounts.find( {
$nor : [
{ name: "alice"},
{ name: "charlie" },
{balance: {$lt: 100 } }
]
})
{ "_id" : ObjectId("63bd1a23ef3b5e682a151ffa"), "name" : "david", "balance" : 200 }
{ "_id" : ObjectId("63bd203cef3b5e682a151ffd"), "name" : "george", "balance" : 1000 }
{ "_id" : ObjectId("63be621def3b5e682a152000"), "name" : "george", "balance" : 1000 }
注意:$nor也会筛选出不包含查询字段的文档
- 读取账户类型不是储蓄账户且余额大于500的银行账户文档
db.accounts.find( {
$nor :[
{ "_id.type": "savings"},
{ balance: { $gt: 500}}
]
})
{ "_id" : "account1", "name" : "alice", "balance" : 100 }
{ "_id" : ObjectId("63bd080fef3b5e682a151ff8"), "name" : "bob", "balance" : 50 }
{ "_id" : ObjectId("63bd1a23ef3b5e682a151ff9"), "name" : "charlie", "balance" : 500 }
{ "_id" : ObjectId("63bd1a23ef3b5e682a151ffa"), "name" : "david", "balance" : 200 }
{ "_id" : ObjectId("63bd1c91ef3b5e682a151ffc"), "name" : "david", "balance" : 20 }
#字段操作符
$exists 匹配包含查询字段的文档
$type 匹配字段类型符合查询值的文档
2.5 字段操作符-$exists
{ field: {$exists: <boolean> } }
- 读取包含账户类型字段的银行账户文档
> db.accounts.find({ "_id.type": {$exists: true} } )
{ "_id" : { "accountNo" : "001", "type" : "savings" }, "name" : "irene", "balance" : 80 }
{ "_id" : { "type" : "savings", "accountNo" : "001" }, "name" : "irene", "balance" : 80 }
回想之前介绍的有些操作符会筛选出不包含查询字段的文档,如果增加一个
$exists操作符,就可以得到更准确的筛选结果
> db.accounts.find( {"_id.type": {$ne: "checking",$exists: true}})
{ "_id" : { "accountNo" : "001", "type" : "savings" }, "name" : "irene", "balance" : 80 }
{ "_id" : { "type" : "savings", "accountNo" : "001" }, "name" : "irene", "balance" : 80 }
2.6 字段操作符-$type
{ field: { $type: <BSON type> } }
{ field: { $type: [ <BSON type1>, <BSON type2>,....]}}
- 读取文档主键是字符串的银行账户文档
> db.accounts.find( { _id: { $type: "string" } } )
{ "_id" : "account1", "name" : "alice", "balance" : 100 }
- 读取文档主键是对象主键或者是复合主键的银行账户文档
> db.accounts.find( { _id: { $type: ["objectId","object"] } } )
{ "_id" : { "accountNo" : "001", "type" : "savings" }, "name" : "irene", "balance" : 80 }
{ "_id" : { "type" : "savings", "accountNo" : "001" }, "name" : "irene", "balance" : 80 }
{ "_id" : ObjectId("63bd080fef3b5e682a151ff8"), "name" : "bob", "balance" : 50 }
{ "_id" : ObjectId("63bd1a23ef3b5e682a151ff9"), "name" : "charlie", "balance" : 500 }
{ "_id" : ObjectId("63bd1a23ef3b5e682a151ffa"), "name" : "david", "balance" : 200 }
{ "_id" : ObjectId("63bd1c91ef3b5e682a151ffc"), "name" : "david", "balance" : 20 }
{ "_id" : ObjectId("63bd203cef3b5e682a151ffd"), "name" : "george", "balance" : 1000 }
{ "_id" : ObjectId("63be621def3b5e682a152000"), "name" : "george", "balance" : 1000 }
- 读取用户姓名是null的银行账户文档
> db.accounts.find( { name: { $type: "null" } } )
- 也可以使用对应的BSON类型序号作为
$type操作符的参数
# 2代表字符串
> db.accounts.find( { _id: { $type: 2 } } )
{ "_id" : "account1", "name" : "alice", "balance" : 100 }
三、数组操作符、运算操作符和文档游标
$all 匹配数组字段中包含所有查询值的文档
$elemMatch 匹配数组字段中至少存在一个值满足筛选条件的文档
3.1 数组操作符-$all
{ <filed>: { $all : [ <value1>, <value2>,...] } }
- 创建包含数组和嵌套数组的文档
db.accounts.insert( [
{
name: "jack",
balance: 2000,
contact: [ "11111111", "Alabama", "US" ]
},
{
name: "karen",
balance: 2500,
contact:[ [ "22222222","33333333"], "Beijing", "China" ]
}
])
- 读取联系地址位于中国北京的银行账户文档
> db.accounts.find( { contact: { $all:[ "China","Beijing"]}})
{ "_id" : ObjectId("63be7ea6ef3b5e682a152002"), "name" : "karen", "balance" : 2500, "contact" : [ [ "22222222", "33333333" ], "Beijing", "China" ] }
- 读取联系电话包含22222222和33333333的银行账户文档
# 因为contact里这个数据时嵌套的,所以这边也用嵌套的数组
> db.accounts.find( { contact: { $all: [ ["22222222","33333333"]]}})
{ "_id" : ObjectId("63be7ea6ef3b5e682a152002"), "name" : "karen", "balance" : 2500, "contact" : [ [ "22222222", "33333333" ], "Beijing", "China" ] }
3.2 数组操作符-$eleMatch
{ <field>: { $elemMatch: { <query1>, <query2>, ... } } }
- 读取联系电话范围在10000000至20000000之间的银行账户文档
> db.accounts.find( { contact: { $elemMatch: { $gt:"10000000", $lt: "20000000"}}})
{ "_id" : ObjectId("63be7ea6ef3b5e682a152001"), "name" : "jack", "balance" : 2000, "contact" : [ "11111111", "Alabama", "US" ] }
将
$all和$elemMatch结合在一起使用
- 读取包含一个在10000000与20000000之间,和一个在20000000至30000000之间的联系电话的银行账户文档
db.accounts.find( {
contact: { $all: [
{ $elemMatch: { $gt: "10000000", $lt: "20000000"}},
{ $elemMatch: { $gt: "20000000", $lt: "30000000"}}
]}
})
没有符合的数据
3.3 运算操作符——$regex
$ regex 匹配满足正则表达式的文档
{ <field>: { : /pattern/, : '<options>' } }
{ <field>: { : /pattern/<option> } }
兼容PCRE v8.41正则表达式库
在和$in操作符一起使用时,只能使用/pattern/<options>
-读取用户姓名以c或者j开头的银行账户文档
> db.accounts.find( {name: { $in: [ /^c/,/^j/ ]}})
{ "_id" : ObjectId("63bd1a23ef3b5e682a151ff9"), "name" : "charlie", "balance" : 500 }
{ "_id" : ObjectId("63be7ea6ef3b5e682a152001"), "name" : "jack", "balance" : 2000, "contact" : [ "11111111", "Alabama", "US" ] }
- 读取用户姓名包含LIE(不区分大小写)的银行账户
> db.accounts.find( { name: { $regex: /LIE/,$options: 'i' }})
{ "_id" : ObjectId("63bd1a23ef3b5e682a151ff9"), "name" : "charlie", "balance" : 500 }
3.4 文档游标
db.collection.find()返回一个文档集合游标
在不迭代游标的情况下,只列出前20个文档
> var myCursor = db.accounts.find()
> myCursor
{ "_id" : "account1", "name" : "alice", "balance" : 100 }
{ "_id" : ObjectId("63bd080fef3b5e682a151ff8"), "name" : "bob", "balance" : 50 }
{ "_id" : ObjectId("63bd1a23ef3b5e682a151ff9"), "name" : "charlie", "balance" : 500 }
{ "_id" : ObjectId("63bd1a23ef3b5e682a151ffa"), "name" : "david", "balance" : 200 }
{ "_id" : ObjectId("63bd1c91ef3b5e682a151ffc"), "name" : "david", "balance" : 20 }
{ "_id" : ObjectId("63bd203cef3b5e682a151ffd"), "name" : "george", "balance" : 1000 }
{ "_id" : { "accountNo" : "001", "type" : "savings" }, "name" : "irene", "balance" : 80 }
{ "_id" : { "type" : "savings", "accountNo" : "001" }, "name" : "irene", "balance" : 80 }
{ "_id" : ObjectId("63be621def3b5e682a152000"), "name" : "george", "balance" : 1000 }
{ "_id" : ObjectId("63be7ea6ef3b5e682a152001"), "name" : "jack", "balance" : 2000, "contact" : [ "11111111", "Alabama", "US" ] }
{ "_id" : ObjectId("63be7ea6ef3b5e682a152002"), "name" : "karen", "balance" : 2500, "contact" : [ [ "22222222", "33333333" ], "Beijing", "China" ] }
- 也可以使用游标下标直接访问文档集合中的某一个文档
> myCursor[1]
{
"_id" : ObjectId("63bd080fef3b5e682a151ff8"),
"name" : "bob",
"balance" : 50
}
游历完游标中所有的文档之后,或者在10分钟之后,游标便会自动
关闭
- 可以使用noCursorTimeout()函数保持游标一直有效
var myCursor= db.accounts.find().noCursorTimeout()
在这之后,在不遍历游标的情况下,需要主动关闭游标
myCursor().close()
- 游标函数
cursor.hasNext() # 如果游标中还有未游历的文档,那么就会返回true,否则返回false
cursor.next() # 指向下一个文档
var myCurosr=db.accounts.find( {name:"george"});
while( myCursor.hasNext() ) {
printjson(myCursor.next());
}
curosr.foreach(<function>) # 遍历游标的文档
var myCurosr=db.accounts.find( {name:"george"});
myCurosr.forEach(printjson)
3.4.1 limit和skip
cursor.limit(<number>) # 返回要求数量的文档
curosr.skip(<offset>) # 跳过指定数量的文档
- 什么都未使用
> db.accounts.find( { name: "george"})
{ "_id" : ObjectId("63bd203cef3b5e682a151ffd"), "name" : "george", "balance" : 1000 }
{ "_id" : ObjectId("63be621def3b5e682a152000"), "name" : "george", "balance" : 1000 }
- 使用
limit
# 通过limit只返回一条数据
> db.accounts.find( { name: "george"}).limit(1)
{ "_id" : ObjectId("63bd203cef3b5e682a151ffd"), "name" : "george", "balance" : 1000 }
- 使用
skip跳过第一条数据
> db.accounts.find( { name: "george"}).skip(1)
{ "_id" : ObjectId("63be621def3b5e682a152000"), "name" : "george", "balance" : 1000 }
- 使用
cursor.limit(0)会返回什么结果?
# 用0相当于没用这个函数
> db.accounts.find( { name: "george"}).limit(0)
{ "_id" : ObjectId("63bd203cef3b5e682a151ffd"), "name" : "george", "balance" : 1000 }
{ "_id" : ObjectId("63be621def3b5e682a152000"), "name" : "george", "balance" : 1000 }
3.4.2 count
cursor.count(<applySkipLimit>) # 默认情况下,<applySkipLimit>为false,即cursor.count()不会考虑cursor.skip()和cursor.limit()的效果
- 当参数为
false(默认)情况下,只考虑find,不考虑limit
> db.accounts.find( { name: "george"}).limit(1).count()
2
- 当参数为
true,开始考虑limit
> db.accounts.find( { name: "george"}).limit(1).count(true)
1
- 在不提供筛选条件时,cursor.count()会从集合的元数据
Metadata中取得结果
> db.accounts.find().count()
11
当数据库分布式结构较为复杂时,元数据中的文档数量可能不准确,在这种情况下,应该避免应用不提供筛选条件的
cursor.count()函数,而使用聚合管道来计算文档数量
3.4.3 sort
cursor.sort(<document>) # 这里的<document>定义了排序的要求,{ field: ordering}
# 1表示由小及大的正向排序,-1表示逆向排序
- 按照余额从大到小,用户姓名按照字母排序的方式排列银行账户文档
> db.accounts.find().sort( { balance:-1,name:1})
{ "_id" : ObjectId("63be7ea6ef3b5e682a152002"), "name" : "karen", "balance" : 2500, "contact" : [ [ "22222222", "33333333" ], "Beijing", "China" ] }
{ "_id" : ObjectId("63be7ea6ef3b5e682a152001"), "name" : "jack", "balance" : 2000, "contact" : [ "11111111", "Alabama", "US" ] }
{ "_id" : ObjectId("63bd203cef3b5e682a151ffd"), "name" : "george", "balance" : 1000 }
{ "_id" : ObjectId("63be621def3b5e682a152000"), "name" : "george", "balance" : 1000 }
{ "_id" : ObjectId("63bd1a23ef3b5e682a151ff9"), "name" : "charlie", "balance" : 500 }
{ "_id" : ObjectId("63bd1a23ef3b5e682a151ffa"), "name" : "david", "balance" : 200 }
{ "_id" : "account1", "name" : "alice", "balance" : 100 }
{ "_id" : { "accountNo" : "001", "type" : "savings" }, "name" : "irene", "balance" : 80 }
{ "_id" : { "type" : "savings", "accountNo" : "001" }, "name" : "irene", "balance" : 80 }
{ "_id" : ObjectId("63bd080fef3b5e682a151ff8"), "name" : "bob", "balance" : 50 }
{ "_id" : ObjectId("63bd1c91ef3b5e682a151ffc"), "name" : "david", "balance" : 20 }
- 读取余额最大的银行账户文档
> db.accounts.find().sort( { balance:-1}).limit(1)
{ "_id" : ObjectId("63be7ea6ef3b5e682a152002"), "name" : "karen", "balance" : 2500, "contact" : [ [ "22222222", "33333333" ], "Beijing", "China" ] }
3.4.4 游标执行顺序
cursor.skip()在cursor.limit()之前执行
# 先从所有文档中通过 skip 跳到第4篇文档,然后再执行 limit 取出5篇文档
> db.accounts.find().limit(5).skip(3)
{ "_id" : ObjectId("63bd1a23ef3b5e682a151ffa"), "name" : "david", "balance" : 200 }
{ "_id" : ObjectId("63bd1c91ef3b5e682a151ffc"), "name" : "david", "balance" : 20 }
{ "_id" : ObjectId("63bd203cef3b5e682a151ffd"), "name" : "george", "balance" : 1000 }
{ "_id" : { "accountNo" : "001", "type" : "savings" }, "name" : "irene", "balance" : 80 }
{ "_id" : { "type" : "savings", "accountNo" : "001" }, "name" : "irene", "balance" : 80 }
cursor.sort()在cursor.skip()和cursor.limit()之前执行
> db.accounts.find().skip(3).limit(5).sort( { balance:-1})
{ "_id" : ObjectId("63be621def3b5e682a152000"), "name" : "george", "balance" : 1000 }
{ "_id" : ObjectId("63bd1a23ef3b5e682a151ff9"), "name" : "charlie", "balance" : 500 }
{ "_id" : ObjectId("63bd1a23ef3b5e682a151ffa"), "name" : "david", "balance" : 200 }
{ "_id" : "account1", "name" : "alice", "balance" : 100 }
{ "_id" : { "accountNo" : "001", "type" : "savings" }, "name" : "irene", "balance" : 80 }
当结合在一起使用时,游标函数的应用顺序是:
sort(),skip(),limit()
3.5 文档投影
db.collection.find(<query>, <projection>)
不使用投影时, db.collection.find()返回符合筛选条件的完整文档
而使用投影可以有选择性的返回文档中的部分字段
{ <filed>: <inclusion>} 1表示返回字段,0 表示不返回字段
- 只返回银行账户文档中的用户姓名
> db.accounts.find({}, { name: 1})
{ "_id" : "account1", "name" : "alice" }
{ "_id" : ObjectId("63bd080fef3b5e682a151ff8"), "name" : "bob" }
{ "_id" : ObjectId("63bd1a23ef3b5e682a151ff9"), "name" : "charlie" }
{ "_id" : ObjectId("63bd1a23ef3b5e682a151ffa"), "name" : "david" }
{ "_id" : ObjectId("63bd1c91ef3b5e682a151ffc"), "name" : "david" }
{ "_id" : ObjectId("63bd203cef3b5e682a151ffd"), "name" : "george" }
{ "_id" : { "accountNo" : "001", "type" : "savings" }, "name" : "irene" }
{ "_id" : { "type" : "savings", "accountNo" : "001" }, "name" : "irene" }
{ "_id" : ObjectId("63be621def3b5e682a152000"), "name" : "george" }
{ "_id" : ObjectId("63be7ea6ef3b5e682a152001"), "name" : "jack" }
{ "_id" : ObjectId("63be7ea6ef3b5e682a152002"), "name" : "karen" }
- 只返回银行账户文档中的用户姓名(不包括文档主键)
> db.accounts.find( {},{name:1,_id:0})
{ "name" : "alice" }
{ "name" : "bob" }
{ "name" : "charlie" }
{ "name" : "david" }
{ "name" : "david" }
{ "name" : "george" }
{ "name" : "irene" }
{ "name" : "irene" }
{ "name" : "george" }
{ "name" : "jack" }
{ "name" : "karen" }
- 不返回银行账户文档中的用户姓名(也不返回文档主键)
> db.accounts.find( {},{name:0,_id:0})
{ "balance" : 100 }
{ "balance" : 50 }
{ "balance" : 500 }
{ "balance" : 200 }
{ "balance" : 20 }
{ "balance" : 1000 }
{ "balance" : 80 }
{ "balance" : 80 }
{ "balance" : 1000 }
{ "balance" : 2000, "contact" : [ "11111111", "Alabama", "US" ] }
{ "balance" : 2500, "contact" : [ [ "22222222", "33333333" ], "Beijing", "China" ] }
除了文档主键之外,我们不可以在投影文档中混合使用包含和不包含这两种投影操作
要么在投影文档中列出所有应该包含的字段,要么列出所有不应该不包含的字段
> db.accounts.find( {},{name:0,balance:1})
Error: error: {
"ok" : 0,
"errmsg" : "Projection cannot have a mix of inclusion and exclusion.",
"code" : 2,
"codeName" : "BadValue"
}
- 在数组字段上使用投影-$slice
$slice操作符可以返回数组字段中的部分元素
# 只返回有contact数组中的第一个元素
> db.accounts.find( {}, {_id:0, name:1, contact:{ $slice: 1 }})
{ "name" : "alice" }
{ "name" : "bob" }
{ "name" : "charlie" }
{ "name" : "david" }
{ "name" : "david" }
{ "name" : "george" }
{ "name" : "irene" }
{ "name" : "irene" }
{ "name" : "george" }
{ "name" : "jack", "contact" : [ "11111111" ] }
{ "name" : "karen", "contact" : [ [ "22222222", "33333333" ] ] }
# 返回有contact字段数组中的倒数第一个元素
> db.accounts.find( {}, {_id:0, name:1, contact:{ $slice: -1 }})
{ "name" : "alice" }
{ "name" : "bob" }
{ "name" : "charlie" }
{ "name" : "david" }
{ "name" : "david" }
{ "name" : "george" }
{ "name" : "irene" }
{ "name" : "irene" }
{ "name" : "george" }
{ "name" : "jack", "contact" : [ "US" ] }
{ "name" : "karen", "contact" : [ "China" ] }
# $slice可以接受至少2个值的数组参数
> db.accounts.find( {}, {_id:0, name:1, contact:{ $slice: [1,2] }})
{ "name" : "alice" }
{ "name" : "bob" }
{ "name" : "charlie" }
{ "name" : "david" }
{ "name" : "david" }
{ "name" : "george" }
{ "name" : "irene" }
{ "name" : "irene" }
{ "name" : "george" }
{ "name" : "jack", "contact" : [ "Alabama", "US" ] }
{ "name" : "karen", "contact" : [ "Beijing", "China" ] }
- 在数组字段上使用投影-
$elemMatch和$操作符可以返回数组字段中满足条件的`第一个元素`
# elemmatch只会返回符合条件的第1个元素
> db.accounts.find( {},
{ _id: 0, name: 1, contact: { $elemMatch: { $gt: "Alabama"}}
}
)
{ "name" : "alice" }
{ "name" : "bob" }
{ "name" : "charlie" }
{ "name" : "david" }
{ "name" : "david" }
{ "name" : "george" }
{ "name" : "irene" }
{ "name" : "irene" }
{ "name" : "george" }
{ "name" : "jack", "contact" : [ "US" ] }
{ "name" : "karen", "contact" : [ "Beijing" ] }1
# 会借用find方法中第一个参数设定好的规则,同时只会返回符合条件的第1个元素
> db.accounts.find(
{ contact: { $gt: "Alabama" } },
{ _id: 0, name: 1, "contact.$":1 }
)
{ "name" : "jack", "contact" : [ "US" ] }
{ "name" : "karen", "contact" : [ "Beijing" ] }