简介
参考文献,菜鸟教程:MongoDB 教程 | 菜鸟教程
MongoDB 是由C++
语言编写的非关系性数据库(也叫NoSQL),是一个基于分布式文件存储的开源数据库系统。在高负载的情况下,添加更多的节点,可以保证服务器性能。
NoSQL
(NoSQL =Not Only SQL
),意即"不仅仅是SQL"。MongoDB 将数据存储为一个文档,数据结构由键值对(key=>value)集合组成。
MongoDB 是介于关系数据库和非关系数据库之间的产品,是非关系数据库中功能最丰富,最像关系数据库的。
-
它有关系型数据库中同等的概念,库,表,数据、指令集以及可扩展的结构,但本质完全不同。
-
关系型数据库中,最重要的是表,所有数据的内外关系 都依赖于表:表结构(行和列)、表连接等
-
Mongo 中
表
称为集合,它是数据库集合的子集 -
mongo中行 称为文档,它没有结构约束,可以设置为任意的键和值。
-
{a : 1}
-
{b : 2}
-
{a:1, b:2, c:3}
-
-
Mongo 不支持关联数据表
-
MongoDB 旨在为WEB应用提供可扩展的高性能数据存储解决方案。
概念
在mongodb中基本的概念是数据库,集合、文档、
SQL术语/概念 | MongoDB术语/概念 | 解释/说明 |
---|---|---|
database | database | 数据库 |
table | collection | 数据库表/集合 |
row | document | 数据记录行/文档 |
column/field | Key | 数据字段/域 |
index | index | 索引 |
table joins | 表连接,MongoDB不支持 | |
primary key | primary key | 主键,MongoDB自动将_id字段设置为主键 |
MongoDB 文档类似于 JSON 对象。字段值可以包含其他文档,数组及文档数组。
mongodb数据库,简单来说,就是一个很大的数据集合:
{
// 数据库
"shop" : {
// 表 在mongo中成为 collection集合
"goods" : {
// 数据行 在mongo中 成为 document文档
"id1" : {
// mongo 没有表结构,也就没有字段(键)的约束
// 每一个文档 它里面可以包含不同的字段(键),但实际业务来说 会有结构设计
gname : '飞利浦',
price : 9527,
“
},
"orders" : {
},
// ...
},
"test" : {
}
}
安装
MongoDB 提供了 OSX 平台上 64 位的安装包,你可以在官网下载安装包。
下载地址:Try MongoDB Products | MongoDB
在macOS系统中,使用curl命令下载文件:
# 进入 /usr/local
cd /usr/local
# 下载
sudo curl -O https://fastdl.mongodb.org/osx/mongodb-osx-ssl-x86_64-4.0.9.tgz
# 解压
sudo tar -zxvf mongodb-osx-ssl-x86_64-4.0.9.tgz
# 重命名为 mongodb 目录
sudo mv mongodb-osx-x86_64-4.0.9/ mongodb
接下来,进入mongodb安装目录下的bin目录,将该地址添加到环境变量,那么你在任意位置都可以执行有关mongo的命令:
$ mongod --version
Mongo 默认使用命令安装位置的根地址 作为数据存放目录,例如c:/data/db
,如果要指定数据存放地址可以通过
--dbpath
来设置:
无论使用何地址,你必须先创建它:
$ cd /usr/local/mongodb
$ sudo mkdir data
$ sudo mkdir -p log/mongodb
对于类unix系统的用户,最好修改目录权限:
$ cd /usr/local/mongodb
$ sudo chown tinlau data
$ sudo chown tinlau log/mongodb
接下来我们使用以下命令在后台启动 mongodb:
$ mongod --dbpath data --logpath log/mongodb/mongo.log --fork
启动成功命令窗口中打印一些启动信息或者在浏览器中输入http://localhost:27017/即可看到显示信息为:
It looks like you are trying to access MongoDB over HTTP on the native driver port.
如果要关闭服务,则可以选择以下几种方式:
-
如果以前台方式启动 MongoDB 服务,使用"Crtl+C"服务会关闭,
这种关闭方式会等待当前进行中的的操作完成,所以依然是干净的关闭方式。
-
使用mongod命令:
mongod --shutdown --dbpath /usr/local/mongodb/data/
-
使用数据库命令关闭 :
> use admin; switched to db admin > db.shutdownServer();
启动服务后 就可以使用mongo
终端访问mongodb
服务:
入门
mongodb用C++高效地实现了底层的数据读写等功能。
对外提供的操作API规则|调用方式,使用了JS来实现,故mongo客户端中使用的命令与JS极度相似。
MongoDB shell
是一个功能完备的JS解释器
,可以运行任何JS程序,那它算一个宿主环境吗?
$ var a = 1;
$ a;
数据库
-
show dbs
查看数据库,显示默认安装的数据库MongoDB的单个实例可以容纳多个独立的数据库,每一个都有自己的集合和权限,不同的数据库也放置在不同的文件中。
-
admin: 从权限的角度来看,这是"root"数据库。要是将一个用户添加到这个数据库,这个用户自动继承所有数据库的权限。一些特定的服务器端命令也只能从这个数据库运行,比如列出所有的数据库或者关闭服务器。
-
local: 这个数据永远不会被复制,可以用来存储限于本地单台服务器的任意集合
-
config: 当Mongo用于分片设置时,config数据库在内部使用,用于保存分片的相关信息。
-
-
db
查看当前所在数据库,默认test,只有当创建了数据 才会真正启用MongoDB的默认数据库为"db",该数据库存储在data目录中。
-
use
切换数据库,如果没有则新建之, -
db.dropDatabase()
删除当前的数据库
集合
集合就是 MongoDB 文档组,类似于 RDBMS (关系数据库管理系统:Relational Database Management System)中的表格。
集合存在于数据库中,集合没有固定的结构,这意味着你在对集合可以插入不同格式和类型的数据,但通常情况下我们插入集合的数据都会有一定的关联性。
比如,我们可以将以下不同数据结构的文档插入到集合中:
{"site":"www.baidu.com"}
{"site":"www.google.com","name":"Google"}
{"site":"www.runoob.com","name":"homey","num":5}
当第一个文档插入时,集合就会被创建。
-
创建集合
db.createCollection("users");
-
查看已有集合
show collections; # 或者 show tables;
-
在 MongoDB 中,你不需要创建集合。当你插入一些文档时,MongoDB 会自动创建集合。
$ db.users.insert({"name" : "homey"}) $ WriteResult({ "nInserted" : 1 })
-
删除集合, 如果成功删除选定集合,则
drop()
方法返回 true,否则返回 false。db.users.drop();
文档
MongoDB 的文档不需要设置相同的字段,并且相同的字段不需要相同的数据类型,这与关系型数据库有很大的区别,这样一来,无需多余操作就可以横向扩展。当第一个文档插入时,集合就会被创建。
-
文档中的
键/值
对是==有序==的。 -
文档中的值不仅可以是在双引号里面的字符串,还可以是其他几种数据类型(甚至可以是整个嵌入的文档)。
-
MongoDB区分类型和大小写。
-
MongoDB的文档不能有重复的键。
-
文档的键是字符串。除了少数例外情况,键可以使用任意UTF-8字符。
CURD
插入文档
MongoDB 使用 insert() 或 save() 方法向集合中插入文档,语法如下:
db.user.insert(document)
若插入的数据主键已经存在,则会抛 org.springframework.dao.DuplicateKeyException 异常,提示主键重复,不保存当前数据
db.user.insertOne(document)
db.user.insertMany([document, document])
如果 _id 主键存在则更新数据,如果不存在就插入数据.
# 插入成功 返回insertedId
{
"acknowledged" : true,
"insertedId" : ObjectId("6167cd8755ce3b28b800ea9a")
}
更新文档
db.collection.update(
<query>,
<update>,
{
upsert: <boolean>,
multi: <boolean>,
writeConcern: <document>
}
)
参数说明:
-
query : update的查询条件,类似
sql update
查询内where后面的。 -
update : update的对象和一些更新的操作符(如$,$inc...)等,也可以理解为sql update查询内set后面的
-
upsert : 可选,这个参数的意思是,如果不存在update的记录,是否插入objNew,true为插入,默认是false,不插入。
-
multi : 可选,mongodb 默认是false,只更新找到的第一条记录,如果这个参数为true,就把按条件查出来多条记录全部更新。
-
writeConcern :可选,抛出异常的级别。
db.user.update({name:'lisi'}, {age:18}); // 重置 覆盖
db.user.update({name:'张三'}, {$set : {gender : '男'}}) // 扩展字段
$set
为修饰器,类似于sql中的set关键字,主要有:$inc $set $unset $push $pull
只更新第一条记录:
db.col.update( { "count" : { $lt : 1 } } , { $set : { "test2" : "OK"} } );
全部更新:
db.col.update( { "count" : { $gt : 3 } } , { $set : { "test2" : "OK"} },false,true );
只添加第一条:
db.col.update( { "count" : { $gt : 4 } } , { $set : { "test5" : "OK"} },true,false );
全部添加进去:
db.col.update( { "count" : { $gt : 5 } } , { $set : { "test5" : "OK"} },true,true );
全部更新:
db.col.update( { "count" : { $gt : 15 } } , { $inc : { "count" : 1} },false,true );
只更新第一条记录:
db.col.update( { "count" : { $gt : 10 } } , { $inc : { "count" : 1} },false,false );
移除数据
MongoDB remove()
函数是用来移除集合中的数据。
MongoDB 数据更新可以使用 update()
函数。在执行 remove()
函数前先执行 find()
命令来判断执行的条件是否正确,这是一个比较好的习惯。
db.collection.remove(
<query>,
{
justOne: <boolean>,
writeConcern: <document>
}
)
-
query :(可选)删除的文档的条件。
-
justOne : (可选)如果设为 true 或 1,则只删除一个文档,如果不设置该参数,或使用默认值 false,则删除所有匹配条件的文档。
-
writeConcern :(可选)抛出异常的级别。
db.users.remove({name:'test'}, {justOne:1})
如果不设置条件,即条件为{}
空对象 则==删除所有==.
查询数据
db.collection.find(query, projection)
-
query :可选,使用查询操作符指定查询条件
-
projection :可选,使用投影操作符指定返回的键。查询时返回文档中所有键值, 只需省略该参数即可(默认省略)。
如果你需要以易读的方式来读取数据,可以使用 pretty()
方法,语法格式如下:
db.collection.find().pretty();
除了 find()
方法之外,还有一个 findOne()
方法,它只返回(第)一个文档:
db.collection.findOne(where);
where子句
MongoDB 与 RDBMS Where 语句比较:
如果你熟悉常规的 SQL 数据,通过下表可以更好的理解 MongoDB 的条件语句查询:
操作 | 格式 | 范例 | RDBMS中的类似语句 |
---|---|---|---|
等于 | {<key>:<value> } | db.col.find({na me:"homey"}).pretty() | where name = 'homey' |
小于 | {<key>:{$lt:<value>}} | db.col.find({count:{$lt:50}}).pretty() | where count < 50 |
小于或等于 | {<key>:{$lte:<value>}} | db.col.find({count:{$lte:50}}).pretty() | where count <= 50 |
大于 | {<key>:{$gt:<value>}} | db.col.find({count:{$gt:50}}).pretty() | where count > 50 |
大于或等于 | {<key>:{$gte:<value>}} | db.col.find({count:{$gte:50}}).pretty() | where count >= 50 |
不等于 | {<key>:{$ne:<value>}} | db.col.find({count:{$ne:50}}).pretty() | where count != 50 |
MongoDB AND 条件:
MongoDB 的 find()
方法可以传入多个键(key),每个键(key)以逗号隔开,即常规 SQL 的 AND 条件。
MongoDB OR 条件:
MongoDB OR 条件语句使用了关键字 $or,语法格式如下:
db.col.find({count: {$gt:50}, $or: [{name:"homey"},{name: "gp7"}]}).pretty()
相当于:where count > 50 and (name='homey' or name='gp7')
模型操作
mongodb
npmjs演示文档:mongodb - npm
mongoose
mongoose是在mongodb模型基础上扩展而来,
参考地址:Mongoose ODM v6.0.10
// 连接mongodb服务器
mongoose.connect('mongodb://localhost/test');
// 创建表模型类 并设置表名,实际会转化成cats,不需要实际存在 当创建了第一条记录 会新建
const Cat = mongoose.model('Cat', { name: String });
// 实例化表 - 创建表并初始数据
const kitty = new Cat({ name: 'Zildjian' });
// 执行
kitty.save().then(() => console.log('meow'));
Schema架构
虽然,mongodb的结构很灵活,但实际业务时 还是会有一定的规范约束以确保数据的一致性与完整性 避免脏值,因此需要设计表结构。moogse是从代码的层面 来支持你对表创建的约束,例如 字段值类型等。
Mongoose为模型提供了一种直接的,基于scheme结构去定义你的数据模型。它内置数据验证, 查询构建,业务逻辑钩子等,开箱即用。
const mongoose = require("mongoose")
const {model, Schema} = mongoose;
// 连接数据库
mongoose.connect("mongodb://localhost/test");
// 设计表结构
const userSec = new Schema({
name : {
type : String,
required : true,
},
gender : {
type : String,
enum : ['m', 'w'],
required : true,
},
age : Number,
})
// 创建表模型类
const User = model("User", userSec);
// 实例化模型类 用来创建数据对象
const users = new User({name : 'lautin', gender : 'w', age : 18});
接下来,可以使用curd方法进行操作,支持promise与回调函数两种方式:
users.save().then(() => {
console.log("done.");
}).catch(e => { // 数据验证不通过时 执行onReject
console.log(e.message);
})
Mongoose 有几个内置的验证器。
-
所有SchemaType都有内置的必需验证器。所需的验证器使用SchemaType 的checkRequired()函数来确定值是否满足所需的验证器。
如果想要自定义错误提示,则配置规则为一个数组或者对象,例如:
const breakfastSchema = new Schema({
eggs: {
type: Number,
min: [6, 'Must be at least 6, got {VALUE}'], //
max: 12
},
drink: {
type: String,
enum: {
values: ['Coffee', 'Tea'],
message: '{VALUE} is not supported'
}
}
});
const Breakfast = db.model('Breakfast', breakfastSchema);
crud方法操作
-
新增:
// 创建数据对象,用于添加的 const model = new Model(data); model.save(); // 数据对象.save()
-
查询:
// 返回所有符合条件的数据 哪怕就一条也是数组 Model.find(where, callback); // 查找符合条件的数据 返回第一条 Model.findOne(where, callback)
-
删除:
// 删除指定条件的记录 Model.remove(where, callback)
[MONGODB DRIVER] Warning: collection.remove is deprecated. Use deleteOne, deleteMany, or bulkWrite instead.
集合.remove()已经不推荐了,使用deleteOne、deleteMany() 或者bulkWrite等替代。
-
修改:
// 按照id查找符合条件的记录 进行修改 findByIdAndUpdate(id, data, callback) // 按照条件查找符合要求的记录 进行修改 findOneAndUpdate(where, data, callback)
封装业务模型
最后,为不同的业务 配置表模型的结构和验证规则以及扩展增删改查操作,例如 商品信息表模型:
const mongoose = require("mongoose");
const {model, Schema} = mongoose;
// 连接数据库
mongoose.connect('mongodb://localhost/goods');
// 设计表
const goodsSchema = new Schema({
gname : String,
gdesc : String,
price : Number,
gpic : String,
created : {
type : String,
default : Date.now()
}
})
const GoodsModel = model("Good", goodsSchema);
module.exports = {
async add (data) {
const goods = new GoodsModel(data);
return await goods.save();
},
async select (where) {
return await GoodsModel.find(where);
},
async delete(where) {
return await GoodsModel.remove(where)
},
async updateById(id, data) {
return GoodsModel.findByIdAndUpdate(id, data)
}
}