MongoDB 是一个基于 分布式文件存储 的开源 NoSQL 数据库系统
用文档存数据,每个文档可以看作是一个键值对集合,类似于 JSON 对象
MongoDB 支持索引以提高查询性能,并且可以在任何属性上创建索引
文档(Document)
- MongoDB 中的基本数据单元是文档(BSON格式),它是一个由键值对组成的数据结构,类似于 JSON 对象。
{ "name": "Alice", "age": 25, "hobbies": ["reading", "swimming"] }
- 文档存储在集合中,支持嵌套和数组等复杂数据结构。
集合(Collection)
- 集合是一组文档的容器,类似于关系数据库中的表。
- 集合中的文档不需要有相同的字段或结构,这提供了很大的灵活性。
数据库(Database)
- 数据库是多个集合的容器。
- 每个数据库都有自己的文件集,并且每个数据库可以包含多个集合
文档操作:
插入文档:
db.users.insertOne(
{
name: "Bob",
age: 30,
hobbies: ["cycling"]
});
db.users.insertMany([
{
name: "Charlie",
age: 35,
hobbies: ["cooking"]
},
{ name: "Diana",
age: 40
}
]);
查询文档:
db.users.find();//查询所有文档
db.users.find({ age: { $gt: 30 } }); // 查找年龄大于30的所有用户
更新操作:
在 MongoDB 中,更新操作针对的是单个集合。MongoDB 中的所有写入操作在单个文档级别都具有原子性
db.users.updateOne({ name: "Alice" }, { $set: { age: 26 } });
db.users.updateMany({ age: { $lt: 30 } }, { $inc: { age: 1 } }); // 将所有年龄小于30的用户年龄加1
删除文档:
db.users.deleteOne({ name: "Bob" });
db.users.deleteMany({ age: { $gte: 40 } }); // 删除所有年龄大于等于40的用户
聚合操作:
可以使用聚合操作来:
- 将来自多个文档的值组合在一起。
- 对集合中的数据进行的一系列运算。
- 分析数据随时间的变化。
MongoDB 提供了两种执行聚合的方法:
聚合管道(Aggregation Pipeline)
执行聚合操作的首选方法。
MongoDB 聚合管道由多个阶段组成,每个阶段在文档通过管道时转换文档。每个阶段接收前一个阶段的输出,进一步处理数据,并将其作为输入数据发送到下一个阶段
每个管道的工作流程是:
- 接受一系列原始数据文档
- 对这些文档进行一系列运算
- 结果文档输出给下一个阶段
使用 db.collection.aggregate() 方法运行的聚合管道不会修改集合中的文档,除非管道包含 $merge或 $out 阶段。
阶段操作符用于 db.collection.aggregate
方法里面
db.collection.aggregate( [ { 阶段操作符:表述 }, { 阶段操作符:表述 }, ... ] )
例子:
db.orders.aggregate([
# 第一阶段:$match阶段按status字段过滤文档,并将status等于"A"的文档传递到下一阶段。
{ $match: { status: "A" } },
# 第二阶段:$group阶段按cust_id字段将文档分组,以计算每个cust_id唯一值的金额总和存储在聚合管道返回的total中。
{ $group: { _id: "$cust_id", total: { $sum: "$amount" } } }
])
//$match相当于where
单一目的聚合方法(Single purpose aggregation methods)
也就是单一作用的聚合函数比如 count()
、distinct()
、estimatedDocumentCount()
。
spring集成:
在 Spring 框架中,Spring Data MongoDB 提供了MongoTemplate
类, 它提供了执行数据库操作的方法,并且支持强类型的查询和结果映射
对于操作的集合名称
- 默认情况下,Spring Data MongoDB 使用实体类的小写类名作为集合名称。
- 可以通过在实体类上使用
@Document(collection = "yourCollectionName")
来指定自定义的集合名称。 - 或者,在调用
MongoTemplate
的方法时,直接通过方法参数指定集合名称,如template.insert(Object object, String collectionName)
template.insert(p);
p = template.findById(p.getId(), Person.class);
template.updateFirst(query(where("name").is("Joe")), update("age", 35), Person.class);
template.remove(p);
//其中p是一个Person类的实例
查询文档:
可以使用Query、Criteria、Aggregation
类来表达查询
其中Criteria
只是定义查询条件的一部分,类似于SQL语句中的where,Criteria是不能单独执行的
Query、Aggregation
一个完整的查询对象,包含了查询条件、排序、分页等信息
Query
适用于简单的查找操作,如根据条件筛选文档、排序、分页等。Aggregation
则用于执行更复杂的数据处理任务,如分组、聚合、数据变换等。Aggregation
可以看作是Query
的高级形式,提供了更多的数据处理能力
//空条件(empty criteria)。这个条件相当于 MongoDB 查询中的 {},也就是匹配所有文档
Criteria criteria = new Criteria();
//Spring Data MongoDB 特有的链式 API 设计方式,方便构建动态查询条件。
criteria.and("name").is("Tom");
//criteria.and("field") 表示:对 "field" 字段添加一个新的条件。
//它内部会自动将这个字段作为新的 where 条件加入到当前的 Criteria 中。
//如果当前 Criteria 还是空的,就相当于从 where("field") 开始。
//完整的查询信息,简单查询
Query query = new Query();
query.addCriteria(Criteria.where("quantity").gt(2));
List<Order> orders = mongoTemplate.find(query, Order.class);
Aggregation aggregation = Aggregation.newAggregation(
// 第一阶段: 筛选购买数量大于2的订单
Aggregation.match(Criteria.where("quantity").gt(2)),
// 第二阶段: 根据商品名称分组,计算总销售额
Aggregation.group("item")
.sum(AggregationExpression.multiply("price", "quantity")).as("totalSales"),
// 第三阶段: 按总销售额降序排列
Aggregation.sort(Sort.by(Sort.Direction.DESC, "totalSales"))
);
//通过match来匹配构建好的criteria查询条件
//然后分阶段进行分组、排序等
//需要通过mongoTemplate.aggregate来执行这个查询语句
//三个参数分别是构建的agg,查询的表,结果的class
AggregationResults<ItemSales> results = mongoTemplate.aggregate(aggregation, "orders", ItemSales.class);
//通过结果getMappedResults提取中目标class的集合
List<ItemSales> mappedResults = results.getMappedResults();
学习资料:MongoDB常见面试题总结(上) | JavaGuide
官方文档