查询文档
- 写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函数返回的结果并不一定准确