查询文档
- 写Demo之前先来做一下初始化操作,创建数据库
use User- 进入数据库
db- 创建集合
db.createcollection('person')- 插入数据
db.person.insert({name: 'BNTang', age: 23}, {name: 'JonathanLee', age: 18})- 正题开始,查询语法如下
db.<collection>.find(
<query>,
<projection>
)- query:查询条件, 相当于MySQL中的where
- projection:投影条件, 规定了结果集中显示那些字段, 相当于MySQL中的 select 字段1, 字段2, .. from 表名;
db.person.find({name:'BNTang'})db.person.find({name:'BNTang'},{_id: 0})查询所有文档
- 语法
db.<collection>.find();- 不传入条件,默认就是查询所有
db.person.find();查询满足条件文档
db.person.insert([{name:'zs', age:17}, {name:'ls', age:18}, {name:'ww', age:19}])单个字段条件查询
- 默认会返回指定集合中所有的数据和所有的字段
db.person.find()- 我们可以通过第一个参数指定查询条件,find方法会把所有满足条件的数据返回给我们
db.person.find({name:'zs'})多个字段条件查询
- 默认是 AND 关系,也就是默认要求同时满足所有指定的条件,才会返回对应的数据
db.person.find({name:'zs', age:17})-
注意点:没有顺序要求,只要是同时满足多个条件即可
db.person.find({age:17, name:'zs'})文档中又是文档的情况
- 插入Demo数据
db.person.insert(
[{name:'zs', age:17, book:{name:'HTML', price:66}},
{name:'ls', age:18, book:{name:'JavaScript', price:88}},
{name:'ww', age:19, book:{name:'Vue', price:199}}]
)- 如果某一个文档的某一个字段的取值又是一个文档,那么在判断的时候我们可以通过
字段.文档属性名称 的方式来判断
db.person.find({'book.name': 'JavaScript'})查询指定字段
-
0表示不显示,1表示显示 - 除主键以外,其它字段不能同时出现
0和1(要么不写,写了就必须全是1或者全是0) - 如果不想查询某一个字段,那么就可以指定这个字段的投影取值为
0
db.person.find({}, {_id: 0})- 如果想查询某一个字段,那么就可以指定这个字段的投影取值为
1 - 默认情况下如果不指定,那么所有字段的投影取值都是
1 - 除了
_id字段以外,其它的字段不能同时出现0和1,同时出现会报错,如下的指令执行就会报错
db.person.find({}, {_id: 0, name: 1, age: 1, book: 0})db.person.find({},{_id:0, book:0})比较操作符
- 和MySQL一样,MongodDB中也支持很多比较操作符
- $eq:等于
- $ne:不等于
- $gt:大于
- $gte:大于等于
- $lt:小于
- $lte:小于等于
使用格式
db.<collection>.find(
{<field>: {$<operator>: <value>}},
<projection>
)Demo
db.person.insert([{name: 'zs', age: 17, gender: '男'}, {name: 'ls', age: 18}, {name: 'ww', age: 19}])- 查询名称叫做
zs的人 - 默认情况下就是按照相等来判断
db.person.find({name: 'zs'})- 如下这里就是明确的告诉MongoDB需要按照相等来查询
db.person.find({name: {$eq: 'zs'}})- 查询所有成年人
db.person.find({age: {$gte: 18}})- 查询所有未成年人
db.person.find({age: {$lt: 18}})- 查询所有不是18岁的人
db.person.find({age: {$ne: 18}})- 注意点:在做不等于判断的时候,没有需要判断的字段,也算作是不等于
- 如下的逻辑就是不等于女的文档查询出来,有的文档连
gender这个字段都没有也会算不等于女,也会被查询出来
db.person.find({gender: {$ne: '女'}})其它比较操作符
- $in:匹配包含在指定值当中的文档
- $nin:匹配除了指定值的文档
- 注意点
- 和
$ne一样,如果没有需要判断的字段,也算作满足条件,意思就是没有某个字段而别的文档又有,如果你没有就是满足条件 - 没有指定字段也算作不包含
- 使用格式
db.<collection>.find(
{<field>: {$<operator>: [<value1>, <value2>, ...]}},
<projection>
)Demo
- 查询名称叫做zs或者ls的人
db.person.find({name: {$in: ['zs', 'ls']}})- 查询名称不叫zs或者ls的人
db.person.find({name: {$nin: ['zs', 'ls']}})- 查询性别不是男或女的人
db.person.find({gender: {$nin: ['男', '女']}})逻辑操作符
- $not:匹配条件不成立的文档
db.<collection>.find(
{<field>: {$not: {<expression>}}}
)- $and:匹配条件全部成立的文档
db.<collection>.find(
{<field>: {$and: [{<expression1>}, {<expression2>}, ...}]}
)- $or:匹配至少一个条件成立的文档
db.<collection>.find(
{<field>: {$or: [{<expression1>}, {<expression2>}, ...}]}
)- $nor:匹配多个条件全部不成立的文档
db.<collection>.find(
{<field>: {$nor: [{<expression1>}, {<expression2>}, ...}]}
)$not
- 查询所有年龄不等于18岁的人
db.person.find({age:{$ne: 18}})db.person.find({age: {$not:{$eq: 18}}})- 查询不是男人的人
- 注意点:$not 运算符和 $ne $nin 一样,如果需要查询的字段不存在,也会算作条件成立
db.person.find({gender:{$not:{$eq:'男'}}})$and
- 查询所有名称叫做zs的未成年人
db.person.find({$and:[{name:{$eq:'zs'}},{age:{$lt:18}}]})db.person.find({$and:[{name:'zs'},{age:{$lt:18}}]})db.person.find({name:'zs', age:{$lt:18}})$or
- 查询所有名称叫做zs或者ls的人
db.person.find({name:{$in:['zs','ls']}})db.person.find({$or:[{name:{$eq:'zs'}},{name:{$eq:'ls'}}]})db.person.find({$or:[{name:'zs'},{name:'ls'}]})$nor
- 查询所有名称不叫zs或者ls的人
db.person.find({name:{$nin:['zs','ls']}})db.person.find({$nor:[{name:'zs'},{name:'ls'}]})- 查询所有名称不叫zs或者性别不是男的人
- 注意点:$nor运算符和 $ne $nin $not一样,如果需要查询的字段不存在,也会算作条件成立
db.person.find({$nor:[{name:'zs'},{gender:'男'}]})字段操作符
- $exists:查询包含某个字段的文档
db.<collection>.find(
{<field>: {$exists: <boolean>}}
)- $type:查询指定字段包含指定类型的文档
db.<collection>.find(
{<field>: {$type: <BSON> or [<BSON1>, <BSON2>]}}
)- 查询包含字段gender的文档
- 插入Demo数据
db.person.insert([
{name:'zs', age:17, gender:'女'},
{name:'ls', age:18},
{name:'ww', age:19},
{name:'BNTang', age:20, gender:'男'}
])- 需求:要求查询出所有拥有gender属性的文档
db.person.find({gender: {$exists: true}})应用场景
- 配合$ne $nin $nor $not 来清理数据
db.person.find({gender:{$ne:'男'}})db.person.find({gender:{$ne:'男', $exists:true}})- 查询所有年龄是字符串类型的文档
db.person.insert([
{name:'bntang', age:'666'},
{name:'jonathanlee', age:'888'}
])- 要求:查询出所有age属性的取值是字符串类型的文档
db.person.find({age:{$type:'string'}})数组操作符
- $all:匹配数组中包含所有指定查询值的文档
db.<collection>.find(
{<field>: {$all: [<value1>, <value2>, ...]}}
)- $elemMatch:匹配数组中至少有一个能完全匹配所有的查询条件的文档
db.<collection>.find(
{<field>: {$elemMatch: {<query1>, <query2>, ...}}}
)Demo
- 查询 tags 中同时拥有html和js的文档
- 插入Demo数据
db.person.insert([
{name: 'zs', tags:['html', 'js', 'vue']},
{name: 'ls', tags:['html', 'react', 'vue']},
{name: 'ww', tags:['html', 'node', 'js']},
])db.person.find({tags:{$all:['html', 'js']}})- 查询所有名称叫做zs,年龄是18岁的文档
db.school.insert([
{class: 'one',
studnets: [
{name:'zs', age: 18},
{name:'ls', age: 19},
{name:'ww', age: 20},
]},
{class: 'two',
studnets: [
{name:'zs', age: 20},
{name:'ls', age: 19},
{name:'ww', age: 18},
]},
])db.school.find({'studnets.name':'ww', 'studnets.age':18})db.school.find({studnets:{$elemMatch:{name:'ww',age:18}}})运算操作符
db.<collection>.find(
{ <field>: { $regex: /pattern/, $options: '<options>' } }
)db.<collection>.find(
{ <field>: { $regex: /pattern/<options> } }
)- 查询满足正则的文档
Demo
db.person.insert([
{name:'zs', age:18},
{name:'ls', age:19},
{name:'ww', age:17},
{name:'Zsf', age:18},
{name:'BNTang', age:19},
{name:'Wz', age:17}
])- 需求:要求查询出所有姓z的人(文档)
db.person.find({name:{$regex:/^z/, $options: 'i'}})- 需求:要求查询出所有姓是z或者l的人(文档)
db.person.find({name:{$in:[/^z/i, /^l/i]}})文档游标
- 为什么学习前端都要学习MongoDB
- 因为MongoDB原生就支持JavaScript,也就是我们可以直接在MongoDB中混入JS代码
- 什么是文档游标
- 我们执行find方法后,find方法其实是有返回值的,find方法会返回一个文档游标(相当于C语言指针)
文档游标常用方法
方法名 | 作用 |
hasNext() | 是否还有下一个文档 |
next() | 取出下一个文档 |
forEach() | 依次取出所有文档 |
- 文档游标注意点
- 默认情况下通过文档游标遍历完所有文档后,系统会在
10分钟后自动关闭当前游标 - 如果不想自动关闭,我们可以通过
noCursorTimeout函数来保持游标一直有效 - 如果想手动关闭游标,我们也可以通过
close函数来手动关闭游标
Demo
- 需求:往person集合中插入
100个文档
var arr =[];
for(var i = 0; i < 100; i++){
arr.push({name:'BNTang: '+i, age:18+i});
}
db.person.insertMany(arr)var cursor = db.person.find().noCursorTimeout()
cursor[0]
cursor[1]var cursor = db.person.find().noCursorTimeout()
while(cursor.hasNext()){
printjson(cursor.next())
}var cursor = db.person.find().noCursorTimeout()
cursor.forEach(printjson)
cursor.close()分页方法
-
cursor.limit(<number>):取多少个文档 -
cursor.skip(<offset>):跳过多少个文档
Demo
- 需求:要求取出前5个文档
var cursor = db.person.find()
cursor.limit(5)- 需求:要求跳过前面的5个文档,取出剩余的所有
var cursor = db.person.find()
cursor.skip(5)- 注意点:我们可以直接在find方法后面调用
limit方法或者skip方法
db.person.find().limit(5)db.person.find().skip(5)分页函数注意点
- 注意点:MongoDB是支持
链式调用的 - 需求:跳过前面5个文档,取出后面的5个文档
db.person.find().skip(5).limit(5)- 注意点:在链式调用的时候,无论
skip写在前面还是后面,都会在limit之前执行
db.person.find().limit(5).skip(10)排序函数
-
cursor.sort({field: ordering, ...}):按照指定规则排序 - ordering为
1表示升序排序 - ordering为
-1表示降序排序
Demo
- 注意点:默认情况下find方法只会返回100个文档
db.person.find()db.person.insert({name:'BNTang6666', age:15})db.person.find().limit(101)db.person.find().sort({age:1})db.person.find().sort({age:-1})- 注意点
- find方法默认只会取出100个文档
- sort函数永远在分页函数之前执行
db.person.find().skip(5).limit(5)db.person.find().skip(5).limit(5).sort({age:-1})统计函数
-
cursor.count(<applySkipLimit>):统计集合中文档的个数 - applySkipLimit默认为false,表示忽略skip和limit
Demo
db.person.find().count()- 注意点
- count函数可以接收一个applySkipLimit参数,通过这个参数可以告诉MongoDB在统计的时候是否需要忽略Skip和Limit
- 默认情况下applySkipLimit的取值是false,表示忽略Skip和Limit
db.person.find().skip(6).count()db.person.find().limit(5).count()db.person.find().skip(6).count({applySkipLimit:true})db.person.find().limit(5).count({applySkipLimit:true})统计函数注意点
- 在find函数不提供筛选条件时,count函数会从集合的元数据中取得结果
- 在单台电脑上是这个结果是准确的
- 但是如果数据库为分布式结构(多台电脑)时
- 如果不给find函数提供筛选条件,那么count函数返回的结果并不一定准确










