MongoDB

MongoDB是一个基于分布式文件存储的非结构化数据数据库,常用于存储大量文本信息。本文介绍了MongoDB的安装(通过Docker),客户端使用,数据库和集合的操作,如创建、删除,以及文档的增删改查,包括查询条件如比较、AND、OR和正则表达式。此外,还讲解了如何在SpringBoot项目中集成和使用MongoDB。
摘要由CSDN通过智能技术生成

一、简介

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();
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值