一、简介
MongoDB 是一个基于分布式文件存储的数据库。由 C++ 语言编写。旨在为 WEB 应用提供可扩展的高性能数据存储解决方案。
- 是一个文档类型数据库
- 数据以
JSON
格式存储 - 一般用于存储大量的非结构化的 文档(文本)数据。例如: 商品的详情、简介,商品的评论信息等
商品的详情:
- 转速 、 类型、 容量、口味: 非结构化数据
只卖iphone: 结构化数据,不需要使用 MongoDB, 只有商品表无法存储所有数据,原因是:不同/相同型号的手机的售价等是不一致的,即使相同型号,售价等信息也可能是不一致的。相同型号,不同参数(颜色、容量、…)的商品是一个商品
在电商环境下 ,商品的最小单元不是商品表,而是 商品的SKU表(统一库存
二、安装
docker
FROM mongo
version: '3.8'
services:
mongo:
build:
context: ./mongo
dockerfile: Dockerfile
container_name: mongo
environment:
MONGO_INITDB_ROOT_USERNAME: root
MONGO_INITDB_ROOT_PASSWORD: root
ports:
- "27017:27017"
三、客户端
进入/安装目录/bin
目录,./mongo
Mongo 客户端为 JS(ES) 脚本语法
也可以使用 Navicat / IDEA 连接Mongo
四、数据库操作
等同于MySQL的库。
命令 | 作用 | 备注 |
---|---|---|
use DATABASE_NAME | 使用库 | 如果数据库不存在,则创建数据库,否则切换到指定数据库。 |
show dbs | 查看所有库 | 没有数据的库不会展示 |
db.dropDatabase() | 删除库 | 删除的是当前使用的库 |
五、集合操作
集合是传统数据库的表的概念。
命令 | 作用 | 备注 |
---|---|---|
db.createCollection(name, options) | 创建集合 | options选项见下图, 当你插入一些文档时,MongoDB 会自动创建集合 |
show collections / show tables | 查看所有集合 | |
db.COLLECTION_NAME.drop() | 删除集合 |
六、文档操作
文档对应传统数据库的数据
1、添加数据
db.COLLECTION_NAME.insert(document) / db.COLLECTION_NAME.save(document)
- save():如果 _id 主键存在则更新数据,如果不存在就插入数据。该方法新版本中已废弃,可以使用 db.collection.insertOne() 或 db.collection.replaceOne() 来代替。 saveOrUpdate
- insert(): 若插入的数据主键已经存在,则会抛 org.springframework.dao.DuplicateKeyException 异常,提示主键重复,不保存当前数据。
2、查询数据
db.collection.find(query, projection)
- query :可选,使用查询操作符指定查询条件: where 后的
- projection :可选,使用投影操作符指定返回的键。查询时返回文档中所有键值, 只需省略该参数即可(默认省略)。select后的内容
如果你需要以易读的方式来读取数据,可以使用 pretty() 方法,语法格式如下:
db.col.find().pretty()
// 第二个参数代表要查询的列
// 语法为{列名:0/1} , 1 代表查询该列 0 代表不查询
// _id 列 默认为 1
db.bb.find({},{"name":0,"address":0});
3、查询条件
3-1 比较条件
db.bb.find({
"age":{ $gte: 22 },
});
3-2 and
MongoDB 的 find() 方法可以传入多个键(key),每个键(key)以逗号隔开,即常规 SQL 的 AND 条件。
db.bb.find({
"age":{ $gte: 22 },
"name":"张三"
});
3-3 or
使用关键字$or
db.col.find(
{
$or: [
{key1: value1}, {key2:value2}
]
}
).pretty()
3-4 练习
// 建表 product
db.createCollection("product")
// 插入数据 可乐 2 23 1000 / 雪碧 3 34 1000 / 芬达 3 10 600
db.product.insert({ name:"可乐",price:2,num:23,rongliang:1000 });
db.product.insert({ name:"雪碧",price:3,num:34,rongliang:1000 });
db.product.insert({ name:"芬达",price:3,num:10,rongliang:600 });
// 查询: 所有价格大于2元 并且 ( 容量 大于 800 或者 库存大于 20 ) 的 所有商品
db.product.find({
price:{ $gt:2 },
$or:[
{ rongliang:{$gt:800} },
{ num:{$gt:20} }
]
});
3-5 like
由于Mongo使用的是JS引擎, 所以可以直接在查询条件中使用正则表达式实现模糊查询
// 支持正则表达式
db.bb.find({
name:/^.*2$/
});
3-6 分页
- limit 查询多少条数据
- skip 跳过多少条数据
db.user.find().limit(n).skip(m) =>
select x from x limit m,n
db.bb.find().limit(2).skip(3);
db.bb.find().limit(pageSize).skip( (pageNo-1)*pageSize );
3-7 排序
// 1 升序 -1 降序 null 为 最小值
db.bb.find().sort({ age:-1 });
对于字符串类型, 按位比较,第一位相同,比第二位
4、复杂对象
db.bb.insert({
name:"abc",
age:22,
score:{
m:99,
eng:100,
chins:80
}
});
db['bb'].find({
"score.eng" : {$gt:90}
});
db.bb.find({
"score.eng" : {$gt:90}
});
5、修改数据
db.collection.update(
<query>,
<update>,
{
upsert: <boolean>,
multi: <boolean>,
writeConcern: <document>
}
)
- query : update的查询条件,类似sql update查询内where后面的。
- update : update的对象,也可以理解为sql update查询内set后面的
- upsert : 可选,这个参数的意思是,如果不存在update的记录,是否插入objNew,true为插入,默认是false,不插入。
- multi : 可选,mongodb 默认是false,只更新找到的第一条记录,如果这个参数为true,就把按条件查出来多条记录全部更新。
- writeConcern :可选,抛出异常的级别。
db.col.update(
{'title':'MongoDB 教程'},
{
$set:
{'title':'MongoDB'}
},
{
multi:true
}
)
6、删除数据
db.collection.remove(
<query>,
<justOne>
)
七、SpringBoot
1、依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
2、配置
spring:
data:
mongodb:
username: kgcshop
password: kgcshop
host: 192.168.137.137
port: 27017
authentication-database: test
database: test
有可能会出现
MongoCommandException: Command failed with error 18 (AuthenticationFailed)
异常原因是: Mongo 中每个库 都有自己的权限管理。所以应该对每个库创建一个子账户, 为子账户授权, 在代码中使用子账户进行管理。
use kgcshop;
db.createUser({
user:'shopuser',
pwd:'shoppwd',
roles:[{
role:'dbOwner',
db:'kgcshop'
}]
});
3、使用Teamplate
3-1 基本使用
@Repository
public class ProductMongoMapperImpl extends BaseMongoMapperImpl<MongoProduct> implements ProductMongoMapper {
}
3-2 基础接口
package cn.kgc.shop.manager.mongo;
import com.mongodb.client.result.DeleteResult;
import com.mongodb.client.result.UpdateResult;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Component;
import java.io.Serializable;
import java.util.List;
import javax.annotation.Resource;
public interface BaseMongoMapper<T> {
/**
* 根据id查询
* @param id
* @return
*/
T findById(Serializable id);
void deleteById(Serializable id);
void updateById(T t);
/**
* 保存数据
*
* @param t
* @return
*/
public T save(T t);
/**
* 查询全部信息
*
* @return
*/
public List<T> find();
/**
* 条件查询
*
* @param query
* @return
*/
public List<T> find(Query query );
/**
* 分页条件查询
*
* @param pageNo 当前页码
* @param pageSize 每页显示条目数
* @param query 查询条件
* @return
*/
public List<T> page(int pageNo, int pageSize, Query query);
/**
* 查询总数
*
* @param query 查询条件
* @return
*/
public long query(Query query );
/**
* 查询单个值
*
* @param query 查询条件
* @param <T>
* @return
*/
public <T> T findOne(Query query) ;
/**
* 查询单个值
*
* @param key 键
* @param value 值
* @param <T>
* @return
*/
public <T> T findOne(String key, Object value);
/**
* 修改单个值
*
* @param query 查询条件
* @param update 修改值
* @return
*/
public long update(Query query, Update update);
/**
* 修改多个值
*
* @param query
* @param update
* @return
*/
public long updates(Query query, Update update);
/**
* 删除匹配到的所有数据
*
* @param query
* @return
*/
public long remove(Query query);
}
package cn.kgc.shop.manager.mongo.impl;
import cn.kgc.shop.manager.mongo.BaseMongoMapper;
import com.mongodb.client.result.DeleteResult;
import com.mongodb.client.result.UpdateResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.mapping.MongoId;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.io.Serializable;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.util.List;
@Component
public class BaseMongoMapperImpl<T> implements BaseMongoMapper<T> {
@Autowired
private MongoTemplate mongoTemplate;
protected static final String DEFAULT_ID = "_id";
private Class clazz;
public BaseMongoMapperImpl() {
// 获取父类的泛型的class对象
clazz = (Class)((ParameterizedType)(this.getClass()
.getGenericSuperclass()))
.getActualTypeArguments()[0];
}
@Override
public T findById(Serializable id) {
return findOne(getIdQuery(id));
}
@Override
public void deleteById(Serializable id) {
remove(getIdQuery(id));
}
@Override
public void updateById(T t) {
Update update = new Update();
Query query = null;
for (Field declaredField : clazz.getDeclaredFields()) {
declaredField.setAccessible(true);
try {
if(declaredField.getAnnotation(MongoId.class) != null){
query = getIdQuery((Serializable) declaredField.get(t));
}
update.set(declaredField.getName(),declaredField.get(t));
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
mongoTemplate.updateMulti(query,update,clazz);
}
private Query getIdQuery(Serializable id){
Query query = new Query();
query.addCriteria(Criteria.where(DEFAULT_ID).is(id));
return query;
}
/**
* 保存数据
*
* @param t
* @return
*/
public T save(T t) {
return mongoTemplate.save(t);
}
/**
* 查询全部信息
* @return
*/
public List<T> find() {
return mongoTemplate.findAll(clazz);
}
/**
* 条件查询
*
* @param query
* @return
*/
public List<T> find(Query query) {
return mongoTemplate.find(query, clazz);
}
/**
* 分页条件查询
*
* @param pageNo 当前页码
* @param pageSize 每页显示条目数
* @param query 查询条件
* @return
*/
public List<T> page(int pageNo, int pageSize, Query query) {
int skip = pageSize * (pageNo - 1);
query.skip(skip).limit(pageSize);
return this.find(query);
}
/**
* 查询总数
*
* @param query 查询条件
* @return
*/
public long query(Query query) {
return mongoTemplate.count(query, clazz);
}
/**
* 查询单个值
*
* @param query 查询条件
* @param <T>
* @return
*/
public <T> T findOne(Query query) {
return (T) mongoTemplate.findOne(query, clazz);
}
/**
* 查询单个值
*
* @param key 键
* @param value 值
* @param <T>
* @return
*/
public <T> T findOne(String key, Object value) {
Query query = Query.query(Criteria.where(key).is(value));
return (T) this.findOne(query);
}
/**
* 修改单个值
*
* @param query 查询条件
* @param update 修改值
* @return
*/
public long update(Query query, Update update) {
UpdateResult updateResult = mongoTemplate.updateFirst(query, update, clazz);
return updateResult.getModifiedCount();
}
/**
* 修改多个值
*
* @param query
* @param update
* @return
*/
public long updates(Query query, Update update) {
UpdateResult updateResult = mongoTemplate.updateMulti(query, update, clazz);
return updateResult.getModifiedCount();
}
/**
* 删除匹配到的所有数据
*
* @param query
* @return
*/
public long remove(Query query) {
DeleteResult deleteResult = mongoTemplate.remove(query, clazz);
return deleteResult.getDeletedCount();
}
}