MongoDB读取文档

查询文档

  • 写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表示显示
  • 除主键以外,其它字段不能同时出现01(要么不写,写了就必须全是1或者全是0)
  • 如果不想查询某一个字段,那么就可以指定这个字段的投影取值为0
db.person.find({}, {_id: 0})
  • 如果想查询某一个字段,那么就可以指定这个字段的投影取值为1
  • 默认情况下如果不指定,那么所有字段的投影取值都是1
  • 除了_id字段以外,其它的字段不能同时出现01,同时出现会报错,如下的指令执行就会报错
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函数返回的结果并不一定准确
posted @ 2020-08-21 15:57  BNTang  阅读(490)  评论(0编辑  收藏  举报