MongoDB之AI伴学

在本次文档中,我将完全依靠通义千文来进行对答式学习。

第一个问题

MongoDB是什么?

MongoDB 是一种 非关系型数据库(NoSQL) ,它用 "文档" 的形式存储数据,类似 JSON 格式。你可以把它想象成一个"灵活的电子表格",但更强大。它的特点是:

  • 灵活:不需要预先定义表结构(比如 MySQL 需要先设计好表格和列),可以直接存储不同结构的数据。例如,用户信息可以有的字段有"地址",有的没有,甚至可以嵌套对象(比如用户地址里包含省、市、街道)。
  • 适合复杂数据:比如存储社交媒体的帖子(包含文字、图片、评论、点赞数等混合类型的数据)。
  • 扩展性强:能轻松处理大数据量,通过"分片"把数据分散到多台服务器上,适合高并发场景。

其中,我命令通义帮我生成了一个实例:

json 复制代码
{
  "user_id": 1,
  "name": "张三",
  "age": 28,
  "email": "[email protected]",
  "addresses": [
    {
      "type": "home",
      "street": "北京市朝阳区XX街道",
      "city": "北京"
    },
    {
      "type": "office",
      "street": "上海市浦东新区YY大厦",
      "city": "上海"
    }
  ],
  "orders": [
    {
      "product": "iPhone 15",
      "price": 8999,
      "purchase_time": "2023-10-01T14:30:00Z"
    },
    {
      "product": "AirPods Pro",
      "price": 1999,
      "purchase_time": "2023-10-02T09:15:00Z"
    }
  ],
  "preferences": {
    "newsletter": true,
    "language": "zh-CN"
  }
}

MongoDB与mysql和redis的区别是什么?

其中,通义向我举了三个比较形象的例子:

  • MySQL 像是"严格的Excel表格",每一行每一列都必须按规则填写,适合需要精确计算和事务的场景(比如银行系统)。

  • MongoDB 像是"灵活的Word文档",可以自由组合文字、图片、表格,适合存储复杂或变化的数据(比如电商的商品详情页,可能包含不同规格的描述)。

  • Redis 像是"快速记忆的临时笔记本",适合存取频繁但生命周期短的数据(比如用户登录状态、热门商品的访问量统计)。

他在后端开发的工程中充当着一个什么样的角色?

MongoDB 的文档模型就像一个"智能文件夹",允许你将复杂、多变的数据(如用户信息、订单、地址)直接打包存储,而无需预先定义严格的结构或通过复杂的关联查询。

个人理解

也就是说,mongoDB本质上也是一个数据库,它和mysql一样是来存储用户的数据的,但是它们本质上是不同的sql是关系型数据库对数据存储之间的格式要求比较严格,而mongoDB更像是一股脑将所有的数据都存储在一个word中,对格式要求没有那么严格。

如何安装?

在官方网站Download MongoDB Community Server | MongoDB下载smi文件

好吧,我还是根据这个博客安装好了

MongoDB的安装配置及使用-阿里云开发者社区

第二个问题

我让通义千问帮我写了一个学习的流程,如下:

  1. 环境准备:安装MongoDB,创建Spring项目,添加依赖。

  2. 配置连接:在application.properties中设置MongoDB的URI。

  3. 创建实体类:使用@Document、@Id等注解。

  4. 创建Repository接口:继承MongoRepository。

  5. 实现基本的CRUD操作:注入Repository,使用save、findById、findAll、delete等方法。

  6. 自定义查询方法:使用@Query注解或方法名约定。

  7. 测试:编写测试类或使用main方法测试功能。

首先在springboot配置MongoDB

配置项目依赖
xml 复制代码
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
连接到MongoDB数据库

创建MongoDB数据库

检查mongodb于springboot是否连接成功

typescript 复制代码
package com.xyu;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.mongodb.core.MongoTemplate;
import static org.springframework.test.util.AssertionErrors.assertNotNull;
@SpringBootTest
class MongodbTestApplicationTests {
    @Autowired
    private MongoTemplate mongoTemplate;
    @Test
    void contextLoads() {
    }
    @Test
    void testMongoDBConnection() {
        // 测试连接是否成功:通过查询数据库名称验证
        String dbName = mongoTemplate.getDb().getName();
        assertNotNull(dbName, "数据库名称不应为null");
        System.out.println("当前连接的数据库: " + dbName);
    }
}
mongoDB的一些基础概念
1. 数据库 (Database)
  • 类比:类似关系型数据库中的 "数据库"。

  • 特点:一个 MongoDB 实例可包含多个独立数据库。

  • 操作

    javascript

    复制

    rust 复制代码
    use mydb  // 切换到 mydb 数据库(不存在则自动创建)
    db.dropDatabase() // 删除当前数据库
2. 集合 (Collection)
  • 类比:类似关系型数据库中的 "表"。

  • 特点

    • 无固定结构:同一集合中的文档可以有不同的字段。
    • 动态创建:插入第一个文档时自动创建。
  • 操作

    javascript

    复制

    scss 复制代码
    db.createCollection("users") // 显式创建集合
    db.users.drop() // 删除集合
3. 文档 (Document)
  • 类比:类似关系型数据库中的 "行"。

  • 本质 :一个 BSON 格式(Binary JSON)的数据结构。

  • 示例

    json

    复制

    css 复制代码
    {
      "_id": ObjectId("507f191e810c19729de860ea"),
      "name": "Alice",
      "age": 30,
      "address": {
        "city": "Beijing",
        "street": "Main Street"
      },
      "hobbies": ["reading", "coding"]
    }
4. _id 字段
  • 作用:每个文档必须有的唯一主键。
  • 默认类型ObjectId(12字节的唯一标识符,包含时间戳、机器ID等)。
  • 自定义:可以手动指定(如使用数字、字符串等)。
增删改查
mongoDB的集合进行增删改查
csharp 复制代码
@Test
void contextLoads() {
    System.out.println("创建一个集合text1");
    mongoTemplate.getDb().createCollection("text1");
    System.out.println("查询集合text1是否存在");
    System.out.println(mongoTemplate.getDb().listCollectionNames().into(new ArrayList<>()).contains("text1"));
    System.out.println("删除集合text1");
    mongoTemplate.getDb().getCollection("text1").drop();
    System.out.println("查询集合text1是否存在");
    System.out.println(mongoTemplate.getDb().listCollectionNames().into(new ArrayList<>()).contains("text1"));
    System.out.println("获取集合的统计信息");
    System.out.println(mongoTemplate.getDb().getCollection("Spring_boot").countDocuments());
    System.out.println("删除所有文档而保留集合");
}
mongoDB的文档进行增删改查

第一个问题:在mongoDB中对文档进行操作时是否需要指定集合?

  • 默认情况下,MongoTemplate 会根据类名来选择集合名称。
  • 如果需要,你可以通过 @Document(collection = "customCollectionName") 来显式指定集合名称。

如果使用默认集合名称当一个集合有多个文档时怎么办?

  • 如果你希望多个不同的类存储在同一个集合中,你可以通过 @Document 注解显式地指定相同的集合名称。所以我建议大家一直使用指定集合方式

  1. 定义实体类:将 Java 类与 MongoDB 集合映射。
  2. 创建 Repository 接口 :使用 MongoRepository 来简化数据操作。
  3. 实现增操作 :使用 save() 方法添加文档。
  4. 调用增操作:通过服务层和控制层将数据插入 MongoDB 集合。
scala 复制代码
package com.xyu.po;
import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Field;
public abstract class Item {
    @Id
    private String id;
    @Field("type")
    private String type;  // 可以根据类型区分具体是 User 还是 Product
    // getter and setter
}

package com.xyu.po;

import org.springframework.data.mongodb.core.mapping.Document;

@Document(collection = "Spring_boot")
public class Product extends Item {
    private String name;
    private double price;
    // 构造函数,getter,setter等
    public Product(String name, double price) {
        super();
        this.name = name;
        this.price = price;
    }
}


package com.xyu.po;
import org.springframework.data.mongodb.core.mapping.Document;
import org.springframework.data.mongodb.core.mapping.Field;
@Document(collection = "Spring_boot")
public class User extends Item {
    private String name;
    private int age;
    // 构造函数,getter,setter等
    public User(String name, int age) {
        super();
        this.name = name;
        this.age = age;
    }
}
kotlin 复制代码
package com.xyu.dao;
import com.xyu.po.User;
import org.springframework.data.mongodb.repository.MongoRepository;
public interface UserRepository extends MongoRepository<User, String> {
    // 可以根据需要定义更多的查询方法
}
java 复制代码
package com.xyu.service;

import com.xyu.dao.UserRepository;
import com.xyu.po.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class UserService {
    @Autowired
    private UserRepository userRepository;
    public void addUser(String name, int age) {
        // 创建一个新的 User 对象
        User user = new User(name, age);
        // 使用 save() 方法插入文档
        userRepository.save(user);
    }
}
ini 复制代码
@Test
void text1(){
    String name = "李华";
    int age = 18;
    userService.addUser(name, age);
}

1. 单个查询步骤

  1. 定义实体类:将 Java 类与 MongoDB 集合映射。
  2. 创建 Repository 接口 :使用 MongoRepository 来简化数据操作。
  3. 实现查询操作 :使用 save() 方法添加文档。
  4. 调用查询操作:通过服务层和控制层将数据插入 MongoDB 集合。
csharp 复制代码
public List<User> getAllUsers() {
    return userRepository.findAll();  // 返回集合中所有文档
}

@Test
void text2(){
    System.out.println(userService.getAllUsers());  // 调用服务层的查询方法
    }
}

2. 多个查询步骤

  • 查询独立的集合 :首先分别查询 UserOrder 集合中的数据。
  • 合并结果 :然后在服务层将结果合并成一个返回值,通常会使用 Map 或其他容器来封装结果。

可以看到数据库中存这两条信息,我们怎么查询不同文档的信息

关键代码:

java 复制代码
package com.xyu.dao;
import com.xyu.po.Item;
import org.springframework.data.mongodb.repository.MongoRepository;
import java.util.List;
public interface ItemRepository extends MongoRepository<Item, String> {
    List<Item> findByType(String type);  // 根据 type 字段查询
}
java 复制代码
package com.xyu.dao;
import com.xyu.po.Item;
import org.springframework.data.mongodb.repository.MongoRepository;
import java.util.List;
public interface ItemRepository extends MongoRepository<Item, String> {
    List<Item> findByType(String type);  // 根据 type 字段查询
}
typescript 复制代码
@Service
public class ItemService {
    @Autowired
    private ItemRepository itemRepository;
    // 根据类型查询所有 Item(例如查询所有 Product 或 User)
    public List<Item> getItemsByType(String type) {
        return itemRepository.findByType(type);  // 按 type 查询
    }
}
ini 复制代码
@Test
void text2(){
    List<Item> products = itemService.getItemsByType("Product");
    System.out.println("Products: " + products);
    List<Item> users = itemService.getItemsByType("User");
    System.out.println("Users: " + users);
    }
}

重点 :合并两个文档类型

ini 复制代码
List<Item> allItems = new ArrayList<>();
allItems.addAll(products);
allItems.addAll(users);
System.out.println(allItems);

3. 聚合查询步骤

  1. 筛选阶段($match) - 像筛子一样先过滤掉不要的数据
    • 例子:只查2023年的订单
  2. 分组阶段($group) - 把相似的数据归为一组
    • 例子:按客户ID分组,计算每个客户的总消费
  3. 排序阶段($sort) - 把结果按规则排队
    • 例子:按销售额从高到低排序
  4. 投影阶段($project) - 决定最终显示哪些字段
    • 例子:只显示客户姓名和总金额,隐藏其他信息

springboot使用聚合查询的筛选阶段($match)选出Product类

python 复制代码
    // 通过聚合查询筛选 type 为 "Product" 的文档
    public List<Product> getProductsByType(String type) {
        Aggregation aggregation = Aggregation.newAggregation(
                Aggregation.match(Criteria.where("type").is(type)) // 使用 $match 筛选 type 字段为 "Product"
        );

        // 执行聚合查询并返回结果
        return mongoTemplate.aggregate(aggregation, "Spring_boot", Product.class).getMappedResults();}

springboot使用分组阶段($group)求和

csharp 复制代码
public double getTotalSpent(String name) {
    // 聚合查询:按产品名称分组,并计算每个产品的总消费金额
    Aggregation aggregation = Aggregation.newAggregation(
            Aggregation.group("name").sum("price").as("totalSpent")  // 按name分组,并计算每个产品的总消费
    );
    // 执行聚合查询并获取结果
    List<Map> results = mongoTemplate.aggregate(aggregation, "Spring_boot", Map.class).getMappedResults();
    System.out.println(results);
    double totalSpent = 0;
    // 遍历查询结果,找出对应名称的消费总金额
    for (Map result : results) {
        if (result.containsKey("_id") && result.get("_id").equals(name)) {
            totalSpent = (double) result.get("totalSpent");
            break;  // 找到匹配的名称后退出循环
        }
    }
    return totalSpent;  // 返回对应名称的总消费金额

排序阶段($sort) - 把结果按规则排队

csharp 复制代码
public List<Map> getTotalSpent1() {
    // 聚合查询:按产品名称分组,并计算每个产品的总消费金额
    Aggregation aggregation = Aggregation.newAggregation(
            Aggregation.group("name").sum("price").as("totalSpent"), // 按name分组,并计算每个产品的总消费
            Aggregation.sort(Sort.by(Sort.Order.desc("totalSpent"))) // 按照总消费金额降序排序
    );

    // 执行聚合查询并获取结果
    List<Map> results = mongoTemplate.aggregate(aggregation, "Spring_boot", Map.class).getMappedResults();
    System.out.println(results);
    return results;
}

投影阶段($project) - 决定最终显示哪些字段

csharp 复制代码
public List<Map> getTotalSpent2() {
    // 聚合查询:按产品名称分组,并计算每个产品的总消费金额
    Aggregation aggregation = Aggregation.newAggregation(
            Aggregation.group("name").sum("price").as("totalSpent"), // 按name分组,并计算每个产品的总消费
            Aggregation.project( "_id")  // 只投影 _id 和 totalSpent 字段
    );
    // 执行聚合查询并获取结果
    List<Map> results = mongoTemplate.aggregate(aggregation, "Spring_boot", Map.class).getMappedResults();
    System.out.println(results);
    return results;
}

csharp 复制代码
public void updateUserAgeByName(String name, int newAge) {
    // 创建查询条件,查找指定名字的用户
    Query query = new Query();
    query.addCriteria(Criteria.where("name").is(name));
    // 创建更新操作,设置新的年龄
    Update update = new Update();
    update.set("age", newAge);
    // 执行更新操作
    mongoTemplate.updateFirst(query, update, User.class);
}

删除

csharp 复制代码
public void deleteUserByName(String name) {
    // 创建查询条件,查找 name 为 "李华" 的用户
    Query query = new Query();
    query.addCriteria(Criteria.where("name").is(name));
    // 执行删除操作
    mongoTemplate.remove(query, User.class);
}
相关推荐
uhakadotcom2 小时前
Python 量化计算入门:基础库和实用案例
后端·算法·面试
小萌新上大分2 小时前
SpringCloudGateWay
java·开发语言·后端·springcloud·springgateway·cloudalibaba·gateway网关
uhakadotcom2 小时前
使用Python获取Google Trends数据:2025年详细指南
后端·面试·github
uhakadotcom2 小时前
使用 Python 与 Google Cloud Bigtable 进行交互
后端·面试·github
直视太阳3 小时前
springboot+easyexcel实现下载excels模板下拉选择
java·spring boot·后端
追逐时光者3 小时前
C#/.NET/.NET Core技术前沿周刊 | 第 33 期(2025年4.1-4.6)
后端·.net
灼华十一3 小时前
Golang系列 - 内存对齐
开发语言·后端·golang
兰亭序咖啡4 小时前
学透Spring Boot — 009. Spring Boot的四种 Http 客户端
java·spring boot·后端
Asthenia04124 小时前
深入解析Pandas索引机制:离散选择与聚合选择的差异及常见误区
后端