MongoDB基础操作命令

51 阅读4分钟

介绍

MongoDB是一个文档数据库(以 JSON 为数据模型),由C++语言编写,旨在为WEB应用提供可扩展的高性能数据存储解决方案。

MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。它支持的数据结构非常松散,数据格式是BSON,一种类似JSON的二进制形式的存储格式,简称Binary JSON,和JSON一样支持内嵌的文档对象和数组对象,因此可以存储比较复杂的数据类型。

Mongo最大的特点是它支持的查询语言非常强大,还支持对数据建立索引。原则上 Oracle 和 MySQL 能做的事情,MongoDB 都能做(包括 ACID 事务)。

MongoDB是一个开源OLTP数据库,它灵活的文档模型(JSON)非常适合敏捷式开发、高可用和水平扩展的大数据应用。

OLTP:on-line Transaction Processing,联机(在线)事务处理

OLAP:on-line Analytical Processing,联机(在线)分析处理

MongoDB vs 关系型数据库

概念对比

image.png

  • 数据库(database):可以理解为逻辑上的名称空间,一个数据库包含多个集合。
  • 集合(collection)--> 表(table),一个集合可以存放多个不同的文档。
  • 文档(document)--> 行(row),一个文档可以存多个字段。
  • 字段(field)--> 列(column):文档中的一个属性。
  • 索引(index):独立的检索式数据结构,与SQL概念一致。
  • _id:每个文档中都拥有一个唯一的_id字段,相当于SQL中的主键primary key
  • 视图(view):可以看作一种虚拟的(非真实存在的)集合,与SQL中的视图类似。从MongoDB 3.4版本开始提供了视图功能,通过聚合管道技术实现。
  • 聚合操作($lookup):MongoDB用于实现“类似”表连接(tablejoin)的聚合操作符。

差异

半结构化:在一个集合中,文档的字段不需要完全相同,并且不需要提前声明;文档还支持多级嵌套数组等数据结构 弱关系:没有外键约束

image.png

应用场景

没有某个业务场景必须要使用MongoDB才能解决,但使用MongoDB通常能让你以更低的成本解决问题。

image.png 只要有一项需求满足就可以考虑使用MongoDB,匹配越多,选择MongoDB越合适。

实操

安装

版本:4.4.X

#下载MongoDB 
wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-4.4.9.tgz 
tar -zxvf mongodb-linux-x86_64-rhel70-4.4.9.tgz

#进入mongodb目录,启动mongodb服务 
mkdir data log 
bin/mongod --port=27017 --dbpath=data --logpath=log/mongodb.log --bind_ip=0.0.0.0 --fork

image.png

利用配置文件启动服务,编辑/mongodb/conf/mongo.conf文件,内容如下:

systemLog:
  destination: file
  path: /mongodb/log/mongod.log # log path
  logAppend: true
storage:
  dbPath: /mongodb/data # data directory
  engine: wiredTiger  #存储引擎
  journal:            #是否启用journal日志
    enabled: true
net:
  bindIp: 0.0.0.0
  port: 27017 # port
processManagement:
  fork: true

启动

mongod -f /mongodb/conf/mongo.conf

关闭服务

bin/mongod --port=27017 --dbpath=data --shutdown

image.png

Mongo shell

基于JavaScript语法,为系统管理员提供了强大的界面,并为开发人员提供了直接测试数据库查询和操作的方法。

bin/mongo --port=27017 

bin/mongo localhost:27017

image.png

常用命令

命令说明
show dbs 、show databases显示数据库列表
use 数据库名切换数据库,如果不存在创建数据库
db.dropDatabase()删除数据库
show collections 、show tables显示当前数据库的集合列表
db.集合名.stats()查看集合详情
db.集合名.drop()删除集合
show users显示当前数据库的用户列表
show roles显示当前数据库的角色列表
show profile显示最近发生的操作
load("xxx.js")执行一个JavaScript脚本文件
exit 、 quit()退出当前shell
help查看mongodb支持哪些命令
db.help()查询当前数据库支持的方法
db.集合名.help()显示集合的帮助信息
db.version()查看数据库版本

创建集合

db.createCollection("emp") 
db.createCollection(name, options)
字段类型描述
capped布尔(可选)如果为true,则创建固定集合。固定集合是指有着固定大小的集合,当达到最大值时,它会自动覆盖最早的文档。
size数值(可选)为固定集合指定一个最大值(以字节计)。如果 capped 为 true,也需要指定该字段。
max数值(可选)指定固定集合中包含文档的最大数量。

安全认证

# 设置管理员用户名密码需要切换到admin库 
use admin 

#创建管理员 
db.createUser({user:"zhkai",pwd:"123456",roles:["root"]}) 

#显示所有用户 
db.system.users.find()

db.dropUser("zhkai") 

#删除当前数据库所有用户  
db.dropAllUser()

# 认证
db.auth(账户名,密码)

image.png

常用权限

权限名描述
read允许用户读取指定数据库
readWrite允许用户读写指定数据库
dbAdmin允许用户在指定数据库中执行管理函数,如索引创建、删除,查看统计或访问system.profile
dbOwner允许用户在指定数据库中执行任意操作,增、删、改、查等
userAdmin允许用户向system.users集合写入,可以在指定数据库里创建、删除和管理用户
clusterAdmin只在admin数据库中可用,赋予用户所有分片和复制集相关函数的管理权限
readAnyDatabase只在admin数据库中可用,赋予用户所有数据库的读权限
readWriteAnyDatabase只在admin数据库中可用,赋予用户所有数据库的读写权限
userAdminAnyDatabase只在admin数据库中可用,赋予用户所有数据库的userAdmin权限
dbAdminAnyDatabase只在admin数据库中可用,赋予用户所有数据库的dbAdmin权限
root只在admin数据库中可用。超级账号,超级权限
db.grantRolesToUser( "zhkai" , [ 
     { role: "clusterAdmin", db: "admin" } ,
     { role: "userAdminAnyDatabase", db: "admin"},
     { role: "readWriteAnyDatabase", db: "admin"} 
 ])

启用鉴权之后,连接MongoDB的相关操作需要提供身份认证

# 鉴权模式启动
bin/mongod --port=27017 --dbpath=data --logpath=log/mongodb.log --bind_ip=0.0.0.0 --fork --auth
# 连接
mongo 192.168.65.174:27017 -u zhakai -p 123456 --authenticationDatabase=admin

image.png

文档

增加单个文档

insertOne: 支持writeConcern,决定一个写操作落到多少个节点上才算成功
db.products.insertOne(
       { "item": "envelopes", "qty": 100, type: "Self-Sealing" },
       { writeConcern: { w : "majority", wtimeout : 100 } }
   );

insert: 若插入的数据主键已经存在,则会抛 DuplicateKeyException 异常,提示主键重复,不保存当前数据。
save: 如果 _id 主键存在则更新数据,如果不存在就插入数据

writeConcern取值

  • 0,发起写操作,不关心是否成功;
  • 1, 写操作需要被写入备份节点才算成功
  • majority,写操作需要被复制到大多数节点上才算成功。

image.png

增加多个文档

db.collection.insertMany(
   { [ <document 1> , <document 2>, ... ] },
   {
      writeConcern: <document>,
      ordered: <boolean>
   }
)
writeConcern, 写入策略,默认为 1,即要求确认写操作,0 是不要求
ordered,指定是否按顺序写入,默认 true,按顺序写入

image.png

脚本插入 编辑脚本book.js

var tags = ["nosql","mongodb","document","developer","popular"];
var types = ["technology","sociality","travel","novel","literature"];
var books=[];
for(var i=0;i<50;i++){
    var typeIdx = Math.floor(Math.random()*types.length);
    var tagIdx = Math.floor(Math.random()*tags.length);
    var favCount = Math.floor(Math.random()*100);
    var book = {
        title: "book-"+i,
        type: types[typeIdx],
        tag: tags[tagIdx],
        favCount: favCount,
        author: "xxx"+i
    };
    books.push(book)
}
db.books.insertMany(books);

进入mongo shell执行

load("books.js")

删除

remove

db.user.remove({age:28})// 删除age 等于28的记录
db.user.remove({age:{$lt:25}})   // 删除age 小于25的记录
db.user.remove( { } ) // 删除所有记录
db.user.remove() //报错

delete(官方推荐)

db.books.deleteMany ({})  //删除集合下全部文档
db.books.deleteMany ({ type:"novel" })  //删除 type等于 novel 的全部文档
db.books.deleteOne ({ type:"novel" })  //删除 type等于novel 的一个文档

返回被删除文档 remove、deleteOne等命令在删除文档后只会返回确认性的信息,如果希望获得被删除的文档,则可以使用findOneAndDelete命令

db.books.findOneAndDelete({type:"novel"})
db.books.findOneAndDelete({type:"novel"},{sort:{favCount:1}}) # 可以实现队列的先进先出。

更新

db.collection.update(
   <query>,  # 查询条件
   <update>, # 更新内容
   {
     upsert: <boolean>,  # 如果不存在更新的记录,是否插入
     multi: <boolean>,   # 是否更新所有符合条件的记录,默认false,只更新找到的第一条
     writeConcern: <document> # 写操作到多少个节点才算成功
   }
)

updateOne:更新单个文档。
updateMany:更新多个文档。
replaceOne:替换单个文档

操作符格式描述
$set{$set:{field:value}}指定一个键并更新值,若键不存在则创建
$unset{$unset : {field : 1 }}删除一个键
$inc{$inc : {field : value } }对数值类型进行增减
$rename{$rename : {old_field_name : new_field_name } }修改字段名称
$push{ $push : {field : value } }将数值追加到数组中,若数组不存在则会进行初始化
$pushAll{$pushAll : {field : value_array }}追加多个值到一个数组字段内
$pull{$pull : {field : _value } }从数组中删除指定的元素
$addToSet{$addToSet : {field : value } }添加元素到数组中,具有排重功能
$pop{$pop : {field : 1 }}删除数组的第一个或最后一个元素
db.books.update(
    {title:"my book"},
    {$set:{tags:["nosql","mongodb"],type:"none",author:"fox"}},
    {upsert:true}
)

Replace update中如果没有操作符,就是替换查询的文档

db.books.update(
    {title:"my book"},
    {justTitle:"my first book"}
)    

findAndModify兼容了查询和修改指定文档的功能,findAndModify只能更新单个文档,默认情况下,findAndModify会返回修改前的“旧”数据。如果希望返回修改后的数据,则可以指定new选项

db.books.findAndModify({
    query:{_id:ObjectId("61caa09ee0782536660494dd")},
    update:{$inc:{favCount:1}},
    new: true
})

查询

db.collection.find( <query filter>, <projection> ).pretty()
query, 指定查询条件,key:value对
projection, 指定返回字段,1,包含该字段;0,排除该字段

db.books.find({"tag": "mongodb"}, {"title":1})

db.books.findOne({"tag": "mongodb"}, {"title":1}) # 查第一条文档

image.png

如果查询返回的条目数量较多,mongo shell则会自动实现分批显示。默认情况下每次只显示20条,可以输入it命令读取下一批。

条件查询

查询条件对照表

SQLMQL
a = 1{a: 1}
a <> 1{a: {$ne: 1}}
a > 1{a: {$gt: 1}}
a >= 1{a: {$gte: 1}}
a < 1{a: {$lt: 1}}
a <= 1{a: {$lte: 1}}

查询逻辑对照表

SQLMQL
a = 1 AND b = 1{a: 1, b: 1}或{$and: [{a: 1}, {b: 1}]}
a = 1 OR b = 1{$or: [{a: 1}, {b: 1}]}
a IS NULL{a: {$exists: false}}
a IN (1, 2, 3){a: {$in: [1, 2, 3]}}

查询逻辑运算符

  • $lt: 存在并小于
  • $lte: 存在并小于等于
  • $gt: 存在并大于
  • $gte: 存在并大于等于
  • $ne: 不存在或存在但不等于
  • $in: 存在并在指定数组中
  • $nin: 不存在或不在指定数组中
  • $or: 匹配两个或多个条件中的一个
  • $and: 匹配全部条件

排序

#指定按收藏数(favCount)降序返回 

db.books.find({type:"travel"}).sort({favCount:-1})

1,升序,  -1,降序

image.png

分页 skip用于指定跳过记录数,limit则用于限定返回结果数量。可以在执行find命令的同时指定skip、limit参数,以此实现分页的功能

# 查第3页数据
db.books.find().skip(8).limit(4)

image.png

巧分页 数据量大的时候,应该避免使用skip/limit形式的分页。

替代方案:使用查询条件+唯一排序条件;

例如:

第一页:db.posts.find({}).sort({_id: 1}).limit(20);

第二页:db.posts.find({_id: {$gt: <第一页最后一个_id>}}).sort({_id: 1}).limit(20);

第三页:db.posts.find({_id: {$gt: <第二页最后一个_id>}}).sort({_id: 1}).limit(20);

处理分页问题 – 避免使用 count

尽可能不要计算总页数,特别是数据量大和查询条件不能完整命中索引时。

考虑以下场景:假设集合总共有 1000w 条数据,在没有索引的情况下考虑以下查询:

db.coll.find({x: 100}).limit(50); db.coll.count({x: 100});

正则表达式

//使用正则表达式查找type包含 so 字符串的book
db.books.find({type:{$regex:"so"}}) 
或者 
db.books.find({type:/so/})

开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第3天,点击查看活动详情