# TestMongoDB **Repository Path**: huang-wenhao1/TestMongoDB ## Basic Information - **Project Name**: TestMongoDB - **Description**: 阿三大撒大撒大撒大撒大撒大撒大苏打 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2025-03-06 - **Last Updated**: 2025-03-14 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 概念 MongoDB是一个开源的文档型数据库管理系统,它使用bson(类似json)格式来存储数据。 MongoDB是一个分布式的NoSQL数据库,它是由一个字段(key)和值对(field:vale)的数据结构。 key类型为string。 MongoDB的文档就是一个bson对象。 database:数据库 collection:集合/数据库表 document:文档/行数据 # 命令 ## 数据库 创建数据库,必须要插入数据才能创建。 ```bash use testbase #如果不创建集合,则默认colName为dbName db.createCollection('testCol') db.testCol.insert({"testDoc":'testValue'}) ``` ![img.png](README.assets/img.png)![img_1.png](README.assets/img_1.png) ```bash #查看所有数据库 show dbs #删除 use 数据库名 db.dropDatabase() ``` ## 集合 ```bash #创建集合 use 数据库名 db.createCollection("集合名") #查询所有集合 use 数据库名 show collections #删除集合 use 数据库名 db.集合名.drop() ``` ## 文档 ### 1、插入 ```bash # 单条插入 use 数据库名 db.集合名.insertOne({ name: "jack", age: 18, sex: "男" }) # 多条插入 # 插入多条文档 use 数据库名 db.集合名.insertMany([ { name: "Bob", age: 30 , sex: "男" }, { name: "Charlie", age: 28 , sex: "男" } ]) ``` ### 2、查询 #### 1、简单查询 ```bash # 查询所有文档 use 数据库名 db.集合名.find() # 条件查询(年龄大于25) use 数据库名 db.集合名.find({ age: { $gt: 25 } }) # 限制返回字段(只返回 name 和 age) use 数据库名 db.集合名.find({}, { name: 1, age: 1, _id: 0 }) # 排序(按年龄降序) 1正序、-1倒叙 use 数据库名 db.集合名.find().sort({ age: -1 }) # 分页(跳过前2条,限制返回5条) use 数据库名 db.集合名.find().skip(2).limit(5) ``` #### 2、聚合查询 ##### match ```bash #过滤文档,类似 SQL 的 WHERE #查询age>29的数据 db.集合名.aggregate( [{ $match: { age: { $gt: 29 } } }] ) ``` ##### group ```bash #过滤文档,类似 SQL 的 WHERE #查询age>29的数据 db.集合名.aggregate([ { $group: { _id: "平均年龄", avgAge: { $avg: "$age" } }} ]); ``` ![image-20250307174239869](README.assets/image-20250307174239869.png) ```bash #格式 db.集合名.aggregate([ { $group: { _id: , : { : } }} ]); #expression1:group的key值 #field:group的value名 ``` accumulator(操作符) $max:最大值 $min:最小值 $avg:平均值... ##### sort / limit / skip 排序 、限制返回数量、跳过 ```bash db.集合名.aggregate([ { $sort: { age: 1 } }, { $skip: 1 }, { $limit: 5 } ]); ``` ##### lookup 类似left join ```bash db.orders.aggregate([ { $lookup: { from: "users", localField: "userId", foreignField: "id", as: "userDetails" } } ]); ``` ```sql #表名为 userDetails SELECT * FROM orders t0 LEFT JOIN users t1 ON t0.userId = t1.id ``` ### 3、更新 ```bash # 更新单条文档(将 name 为 jack 的 age 改为26) use 数据库名 db.集合名.updateOne( { name: "jack" }, { $set: { age: 26 } } ) # 更新多条文档(所有 age 大于25的文档添加 status 字段) use 数据库名 db.集合名.updateMany( { age: { $gt: 25 } }, { $set: { status: "active" } } ) # 替换文档(完全替换匹配的文档) use 数据库名 db.集合名.replaceOne( { name: "Bob" }, { name: "Bob", age: 31, role: "admin" } ) ``` ### 4、删除 ```bash # 删除单条文档(删除 name 为 jack 的文档) use 数据库名 db.集合名.deleteOne({ name: "jack" }) # 删除多条文档(删除 age 小于28的文档) use 数据库名 db.集合名.deleteMany({ age: { $lt: 28 } }) ``` ## 索引 ### 1、创建 索引名为 被索引字段_排序方式 ```bash #单字段索引(按 name 升序) use 数据库名 db.集合名.createIndex({name: 1}) #复合索引(按 name 升序和 age 降序),名为name_1、age_-1 use 数据库名 db.集合名.createIndex({name: 1,age: -1}) # 唯一索引(确保 email 唯一) use 数据库名 db.users.createIndex({ email: 1 }, { unique: true }) ``` ### 2、查看 ```bash use 数据库名 db.集合名.getIndexes() ``` ### 3、删除 ```bash # 根据索引名称删除 use 数据库名 db.集合名.dropIndex("name_1") ``` # 设置用户 ## 下载mongosh 6.0后没有mongodb shell 1. 下载mongosh压缩包https://www.mongodb.com/try/download/shell 2. 解压后,复制bin下两个文件,复制到mongodb的bin下 3. cmd测试mongosh ## 创建超级用户 用于管理其他用户 ```bash > use admin > db.CreateUser( { user: "admin", pwd: "123456", roles: [ {role: "userAdminAnyDatabase", db: "admin"}, "readWriteAnyDatabase" // 可以不设置此项,只是为了开发方便 ] } #结果查看 > show users ``` ## 创建目标用户 用于对应数据库的用户 ```bash > use testbase // 切换数据库 (此数据库既是 database,后续也作为 user 认证的 authentication-database > db.CreateUser( { user: "test", pwd: "123456", roles: [ {role: "dbOwner", db: "testbase"} ] } > show users ``` MongoDB角色链接:https://blog.csdn.net/qq_38008567/article/details/141389956 # 集成SpringBoot ## 依赖 ```xml org.springframework.boot spring-boot-starter-data-mongodb ``` ## 创建用户 ```bash use admin db.createUser( { user:'user', pwd :'123', roles:[ { role:'userAdminAnyDatabase',db:'admin' } ] } ) ``` ## application.yml ```yaml spring: data: mongodb: port: 27017 username: test #用户名 password: "123456" #如果是纯数字需要加引号转为字符串 host: localhost authentication-database: test #用户名 database: testbase #数据库 ``` ## 注解 ### @Document 把一个java类声明为[mongodb](https://so.csdn.net/so/search?q=mongodb&spm=1001.2101.3001.7020)的文档,可以通过collection参数指定这个类对应的集合。 ### @MongoId/Id 文档的唯一标识,在mongodb中为ObjectId,它是唯一的,不可重复,自带索引,通过[时间戳](https://so.csdn.net/so/search?q=时间戳&spm=1001.2101.3001.7020)+机器标识+进程ID+自增计数器(确保同一秒内产生的Id不会冲突)构成。 ```java @Id private Integer id; ``` ### @Transient 映射忽略的字段,该字段不会保存到mongodb,只作为普通的[javaBean](https://so.csdn.net/so/search?q=javaBean&spm=1001.2101.3001.7020)属性。 ```java @Transient private String name; ``` ### @Field 映射 mongodb中的字段名或类型,可以不加,不加的话默认以参数名为列名。 ==**如果为bigdecimal类型,需要@Field(targetType = FieldType.DECIMAL128)否则插入mongo里面为string**== ```java @Field private Integer age; ``` ### @Indexed 声明该字段需要索引,建索引可以大大的提高查询效率。 ```java @Indexed private Integer age; ``` ### @CompoundIndex 复合索引的声明,建复合索引可以有效地提高多字段的查询效率。 注解在类、接口、枚举 ```java @CompoundIndexes(@CompoundIndex(name = "name_age_idx",def = "{'name':1,'age',-1}")) public class User { ... } ``` ### @GeoSpatialIndexed 声明该字段为地理信息的索引。 ### @DBRef 关联另一个document对象。类似于mysql的表关联,但并不一样,mongo不会做级联的操作。 ```java @Document(collection = "Books") @Data public class Book { @Id private ObjectId id; private String name; private Double price; @DBRef(lazy = true) private Chapter chapter;//支持List } @Document(collection = "Chapters") @Data public class Chapter { @JsonSerialize(using = ObjectIdSerializer.class) @JsonDeserialize(using = ObjectIdDeserializer.class) @Id private ObjectId id; private String name; private String content; } ``` ```bash { "name":"小明", "book":{ "name":"Go语言入门", "price":39.9, "chapter":{ "name":"第一章", "content":"认识GO初级语法" } } } ``` ## 示例 ### 实体类 ```java @Data @Document("user") public class User { @TableId(value = "uid", type = IdType.ASSIGN_ID) @MongoId private Integer uid; private String name; private String password; private Integer age; private Bigdecimal salary; } ``` ### 集合 #### 1、新增 ```java @Test void testCol() { mongoTemplate.createCollection("springTestDB"); Set collectionNames = mongoTemplate.getCollectionNames(); System.out.println(collectionNames); } ``` ![image-20250310114258879](README.assets/image-20250310114258879.png) ### 文档 #### 1、插入文档 ```java @Test void testInsertDoc() throws Exception { // 插入文档 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Date date1 = sdf.parse("2025-03-13 15:30:00"); Date date2 = sdf.parse("2024-05-01 12:00:00"); Date date3 = sdf.parse("2025-03-13 8:00:00"); Date date4 = sdf.parse("2025-02-11 10:29:00"); SimpleDateFormat sdf1 = new SimpleDateFormat("yyyy-MM-dd"); User user1 = new User("1", "jack", "123", 18, new BigDecimal(4300), sdf1.parse("2000-09-26"), date1); User user2 = new User("2", "mary", "123", 25, new BigDecimal(5000), sdf1.parse("2002-06-06"), date2); User user3 = new User("3", "tom", "123", 30, new BigDecimal(7500), sdf1.parse("1999-01-24"), date3); User user4 = new User("4", "peter", "123", 30, new BigDecimal(9000), sdf1.parse("1989-5-27"), date4); mongoTemplate.save(user1); mongoTemplate.save(user2); mongoTemplate.save(user3); mongoTemplate.save(user4); } ``` ==**插入时间,navicat显示会-8h。**== #### 2、查询文档 ```java @Test void testQueryDoc() { //所有文档 List list = mongoTemplate.findAll(User.class); //id查询 mongoTemplate.findById(1,User.class); //多条件 Query query = new Query(); query.addCriteria(Criteria.where("name").is("jack")); query.addCriteria(Criteria.where("age").gte(18)); List users = mongoTemplate.find(query, User.class); //排序 Query sortQuery = new Query(); sortQuery.with(Sort.by(Sort.Order.desc("age"))); List users = mongoTemplate.find(sortQuery, User.class); //分页 Query pageQuery = new Query(); pageQuery.skip(0).limit(2); List users = mongoTemplate.find(pageQuery, User.class); //json等值查询 Query basicQuery = new BasicQuery("{name: 'jack'}"); List users = mongoTemplate.find(basicQuery, User.class); System.out.println(users); //json条件查询 Query basicQueryMul = new BasicQuery("{age: {$gte: 25}}"); List usersMul = mongoTemplate.find(basicQueryMul, User.class); System.out.println(usersMul); } ``` #### 3、修改文档 ```java @Test void testUpdateDoc() { // 更新第一个文档 Query upQuery = new Query(); upQuery.addCriteria(Criteria.where("name").is("jack")); Update update = new Update(); update.set("age", 19); UpdateResult updateFirstResult = mongoTemplate.updateFirst(upQuery, update, User.class); System.out.println(updateFirstResult); // 更新所有文档 Query upQueryMul = new Query(); upQueryMul.addCriteria(Criteria.where("password").is("123")); Update updateMul = new Update(); updateMul.set("age", 19); UpdateResult updateResult = mongoTemplate.updateMulti(upQueryMul, updateMul, User.class); System.out.println(updateResult); //不存在则插入,不设置_id则自动生成 Query queryUpsert = new Query(); queryUpsert.addCriteria(Criteria.where("name").is("julie")); Update upsert = new Update(); upsert.set("age", 33); UpdateResult upsertResult = mongoTemplate.upsert(queryUpsert, upsert, User.class); System.out.println(upsertResult); } ``` #### 4、删除文档 ```java @Test void testDelDoc() { //条件删除 Query query = new Query(); query.addCriteria(Criteria.where("name").is("julie")); DeleteResult remove = mongoTemplate.remove(query, User.class); System.out.println(remove); //删除集合下文档 mongoTemplate.remove(new Query(),User.class); //直接删除集合 mongoTemplate.dropCollection("user"); } ``` #### 5、聚合操作 ```java //聚合查询 @Test void testAggDoc() { //使用Aggregates(偏底层) MongoCollection collection = mongoTemplate.getCollection("user"); Bson matchBson = Aggregates.match(new Document("password", "123")); Bson ageBson = Aggregates.sort(Sorts.descending("age")); ArrayList bsons = new ArrayList<>(); bsons.add(matchBson); bsons.add(ageBson); AggregateIterable result = collection.aggregate(bsons); result.forEach(System.out::println); //使用Aggregation(spring api)推荐 MatchOperation match = Aggregation.match(Criteria.where("password").is("123")); SortOperation sort = Aggregation.sort(Sort.Direction.ASC, "age"); TypedAggregation userTypedAggregation = Aggregation.newAggregation(User.class, match, sort); //这里查询结果用Document接收,可以修改结果属性 AggregationResults aggregate = mongoTemplate.aggregate(userTypedAggregation, Document.class); List results = aggregate.getMappedResults(); results.forEach(System.out::println); } ``` ##### 1、分组 ```java @Test void testAggGroupDoc() { GroupOperation group = Aggregation.group("age").addToSet("uid").as("ids").first("name").as("name"); TypedAggregation userTypedAggregation = Aggregation.newAggregation(User.class, group); AggregationResults aggregate = mongoTemplate.aggregate(userTypedAggregation, Document.class); List results = aggregate.getMappedResults(); results.forEach(System.out::println); } ``` ```bash #结果 Document{{_id=18, ids=[1], name=jack}} Document{{_id=25, ids=[2], name=mary}} Document{{_id=30, ids=[4, 3], name=tom}} ``` ##### 2、统计 ###### 1、分组 ```java @Test void testAggAvgDoc() { GroupOperation group = Aggregation.group("age").sum("salary").as("total_salary"); TypedAggregation userTypedAggregation = Aggregation.newAggregation(User.class, group); AggregationResults aggregate = mongoTemplate.aggregate(userTypedAggregation, Document.class); List results = aggregate.getMappedResults(); results.forEach(System.out::println); } ``` ```bash #原始数据 User(uid=1, name=jack, password=123, age=18, salary=4300) User(uid=2, name=mary, password=123, age=25, salary=5000) User(uid=3, name=tom, password=123, age=30, salary=7500) User(uid=4, name=peter, password=123, age=30, salary=9000) #结果 Document{{_id=25, total_salary=5000}} Document{{_id=18, total_salary=4300}} Document{{_id=30, total_salary=16500}} ``` ###### 2、时间 ```java @Test void testAggDate() throws Exception { // 定义日期格式 SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); // 解析日期字符串 Date date = sdf.parse("2000-09-26"); MatchOperation match = Aggregation.match(Criteria.where("birthday").lt(date)); TypedAggregation userTypedAggregation = Aggregation.newAggregation(User.class, match); AggregationResults aggregate = mongoTemplate.aggregate(userTypedAggregation, User.class); List results = aggregate.getMappedResults(); results.forEach(System.out::println); } ``` 文档怎么确定自己在哪个集合中?因为在实体类中设置了@Document("集合名),所以当使用该实体类会自动使用该集合。 当然,mongoTemplate每个操作mongo的方法都可以通过传入collectionName指定集合。 ## MongoRepository 通过继承MongoRepository接口,可以执行常见的CRUD。 接口通过方法命名约定来推断查询逻辑 ### interface ```java public interface UserRepository extends MongoRepository { Page findByPasswordOrderByRegisterTimeDesc(String pwd, Pageable pageable); } ``` ### test ```java @Test void testRepository() throws Exception { Pageable pageable = PageRequest.of(0, 3); Page page = userRepository.findByPasswordOrderByRegisterTimeDesc("123", pageable); System.out.println(page.getTotalPages()); } ``` 其中查询参数和方法名对应。 findByPassword对应pwd