MongoDB 聚合操作,有手就行?

家人们!今天咱要勇闯 MongoDB 聚合操作的 "数据魔法学院"!这玩意儿就像数据库界的 "满汉全席厨师",能把杂乱无章的数据食材,加工成老板看了直呼 "好家伙" 的分析报表!不管你是刚入门的小白,还是想进阶的老鸟,跟着我这波操作,保准让你从 "厨房帮工" 变身 "米其林大厨"!

一、食材准备:定义数据菜单

先给大家瞅瞅咱们的 "数据菜谱"------ 假设咱有个 orders 集合,专门存订单信息,每个文档长这样:

json 复制代码
{
    "orderId": "123",
    "customer": "Alice",
    "products": [
        {
            "productName": "Laptop",
            "price": 1000,
            "quantity": 1
        },
        {
            "productName": "Mouse",
            "price": 20,
            "quantity": 2
        }
    ],
    "orderDate": "2024-01-01"
}

有了这些数据食材,咱们的聚合魔法盛宴正式开席!

二、基础操作:厨房入门三件套

1. $match:食材质检员

$match 堪称数据界的 "质检员",专门把不符合要求的食材挑出去!比如咱们只要 2024 年 1 月 1 日后的订单:

ini 复制代码
import com.mongodb.client.AggregateIterable;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import org.bson.Document;
import static com.mongodb.client.model.Aggregates.match;
import static com.mongodb.client.model.Filters.gt;
public class MatchExample {
    public static void main(String[] args) {
        MongoClient mongoClient = MongoClients.create("mongodb://localhost:27017");
        MongoDatabase database = mongoClient.getDatabase("testdb");
        MongoCollection<Document> collection = database.getCollection("orders");
        // 对应MongoDB查询语句:db.orders.aggregate([{ $match: { orderDate: { $gt: "2024-01-01" } } }])
        AggregateIterable<Document> result = collection.aggregate(List.of(
                match(gt("orderDate", "2024-01-01"))
        ));
        for (Document document : result) {
            System.out.println(document);
        }
    }
}

这波操作,就像把过期食材全扔了,只留下新鲜的!

2. $project:食材整形师

$project 是数据界的 "整形医生",能决定哪些字段要 "露脸"!比如咱们只要 orderId 和 customer 字段:

ini 复制代码
import com.mongodb.client.AggregateIterable;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import org.bson.Document;
import static com.mongodb.client.model.Aggregates.project;
import static com.mongodb.client.model.Projections.fields;
import static com.mongodb.client.model.Projections.include;
public class ProjectExample {
    public static void main(String[] args) {
        MongoClient mongoClient = MongoClients.create("mongodb://localhost:27017");
        MongoDatabase database = mongoClient.getDatabase("testdb");
        MongoCollection<Document> collection = database.getCollection("orders");
        // 对应MongoDB查询语句:db.orders.aggregate([{ $project: { orderId: 1, customer: 1, _id: 0 } }])
        AggregateIterable<Document> result = collection.aggregate(List.of(
                project(fields(include("orderId", "customer"), include("_id", 0)))
        ));
        for (Document document : result) {
            System.out.println(document);
        }
    }
}

这就好比给数据做了个 "美颜",只留下咱想看的部分!

3. $sort:食材排序员

$sort 是数据界的 "强迫症晚期患者",非要把数据按顺序排得明明白白!比如按订单日期降序排列:

ini 复制代码
import com.mongodb.client.AggregateIterable;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import org.bson.Document;
import static com.mongodb.client.model.Aggregates.sort;
import static com.mongodb.client.model.Sorts.descending;
public class SortExample {
    public static void main(String[] args) {
        MongoClient mongoClient = MongoClients.create("mongodb://localhost:27017");
        MongoDatabase database = mongoClient.getDatabase("testdb");
        MongoCollection<Document> collection = database.getCollection("orders");
        // 对应MongoDB查询语句:db.orders.aggregate([{ $sort: { orderDate: -1 } }])
        AggregateIterable<Document> result = collection.aggregate(List.of(
                sort(descending("orderDate"))
        ));
        for (Document document : result) {
            System.out.println(document);
        }
    }
}

这下数据全都整整齐齐,找起来超方便!

三、中级操作:进阶烹饪技巧

1. $group:食材分类员

$group 就像超市的 "货架管理员",把相似的数据分到同一类!比如统计每个客户的订单总金额:

dart 复制代码
import com.mongodb.client.AggregateIterable;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import org.bson.Document;
import static com.mongodb.client.model.Aggregates.group;
import static com.mongodb.client.model.Aggregates.project;
import static com.mongodb.client.model.Aggregates.unwind;
import static com.mongodb.client.model.Accumulators.sum;
import static com.mongodb.client.model.Projections.fields;
import static com.mongodb.client.model.Projections.include;
public class GroupExample {
    public static void main(String[] args) {
        MongoClient mongoClient = MongoClients.create("mongodb://localhost:27017");
        MongoDatabase database = mongoClient.getDatabase("testdb");
        MongoCollection<Document> collection = database.getCollection("orders");
        // 对应MongoDB查询语句:
        // db.orders.aggregate([
        //     { $unwind: "$products" },
        //     {
        //         $group: {
        //             _id: "$customer",
        //             totalAmount: { $sum: { $multiply: [ "$products.price", "$products.quantity" ] } }
        //         }
        //     },
        //     {
        //         $project: {
        //             customer: "$_id",
        //             totalAmount: 1,
        //             _id: 0
        //         }
        //     }
        // ])
        AggregateIterable<Document> result = collection.aggregate(List.of(
                unwind("$products"),
                group("$customer", sum("totalAmount", new Document("$multiply", Arrays.asList("$products.price", "$products.quantity")))),
                project(fields(include("customer", "$_id"), include("totalAmount"), include("_id", 0)))
        ));
        for (Document document : result) {
            System.out.println(document);
        }
    }
}

有了这招,老板问 "每个客户花了多少钱",咱直接甩数据,超有排面!

2. $unwind:食材拆解师

<math xmlns="http://www.w3.org/1998/Math/MathML"> u n w i n d 就像把一捆菜拆开的"拆包大师",专门对付数组类型的数据!在上面 unwind 就像把一捆菜拆开的 "拆包大师",专门对付数组类型的数据!在上面 </math>unwind就像把一捆菜拆开的"拆包大师",专门对付数组类型的数据!在上面group 算总金额时,就用它拆开 products 数组:

ini 复制代码
import com.mongodb.client.AggregateIterable;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import org.bson.Document;
import static com.mongodb.client.model.Aggregates.unwind;
public class UnwindExample {
    public static void main(String[] args) {
        MongoClient mongoClient = MongoClients.create("mongodb://localhost:27017");
        MongoDatabase database = mongoClient.getDatabase("testdb");
        MongoCollection<Document> collection = database.getCollection("orders");
        // 对应MongoDB查询语句:db.orders.aggregate([{ $unwind: "$products" }])
        AggregateIterable<Document> result = collection.aggregate(List.of(
                unwind("$products")
        ));
        for (Document document : result) {
            System.out.println(document);
        }
    }
}

这操作,让复杂的数组数据瞬间变得 "服服帖帖"!

四、高阶操作:顶级烹饪秘籍

1. $lookup:跨仓库取材

$lookup 简直是数据界的 "哆啦 A 梦",能从别的集合里 "掏" 数据过来!假设咱有个 customers 集合存客户详情,想把订单和客户信息关联起来:

typescript 复制代码
import com.mongodb.client.AggregateIterable;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import org.bson.Document;
import static com.mongodb.client.model.Aggregates.lookup;
public class LookupExample {
    public static void main(String[] args) {
        MongoClient mongoClient = MongoClients.create("mongodb://localhost:27017");
        MongoDatabase database = mongoClient.getDatabase("testdb");
        MongoCollection<Document> collection = database.getCollection("orders");
        // 对应MongoDB查询语句:
        // db.orders.aggregate([
        //     {
        //         $lookup: {
        //             from: "customers",
        //             localField: "customer",
        //             foreignField: "name",
        //             as: "customerDetails"
        //         }
        //     }
        // ])
        AggregateIterable<Document> result = collection.aggregate(List.of(
                lookup("customers", "customer", "name", "customerDetails")
        ));
        for (Document document : result) {
            System.out.println(document);
        }
    }
}

这波操作,就像把不同仓库的食材凑到一起,做出超豪华套餐!

2. $facet:同时做大餐

$facet 是数据界的 "时间管理大师",能同时执行多个聚合任务!比如咱同时统计每个客户的订单数和总金额:

dart 复制代码
import com.mongodb.client.AggregateIterable;
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoClient;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.MongoDatabase;
import org.bson.Document;
import static com.mongodb.client.model.Aggregates.facet;
import static com.mongodb.client.model.Aggregates.group;
import static com.mongodb.client.model.Aggregates.project;
import static com.mongodb.client.model.Aggregates.unwind;
import static com.mongodb.client.model.Accumulators.sum;
import static com.mongodb.client.model.Projections.fields;
import static com.mongodb.client.model.Projections.include;
public class FacetExample {
    public static void main(String[] args) {
        MongoClient mongoClient = MongoClients.create("mongodb://localhost:27017");
        MongoDatabase database = mongoClient.getDatabase("testdb");
        MongoCollection<Document> collection = database.getCollection("orders");
        // 对应MongoDB查询语句:
        // db.orders.aggregate([
        //     {
        //         $facet: {
        //             orderCountByCustomer: [
        //                 {
        //                     $group: {
        //                         _id: "$customer",
        //                         orderCount: { $sum: 1 }
        //                     }
        //                 },
        //                 {
        //                     $project: {
        //                         customer: "$_id",
        //                         orderCount: 1,
        //                         _id: 0
        //                     }
        //                 }
        //             ],
        //             totalAmountByCustomer: [
        //                 { $unwind: "$products" },
        //                 {
        //                     $group: {
        //                         _id: "$customer",
        //                         totalAmount: { $sum: { $multiply: [ "$products.price", "$products.quantity" ] } }
        //                     }
        //                 },
        //                 {
        //                     $project: {
        //                         customer: "$_id",
        //                         totalAmount: 1,
        //                         _id: 0
        //                     }
        //                 }
        //             ]
        //         }
        //     }
        // ])
        AggregateIterable<Document> result = collection.aggregate(List.of(
                facet(
                        "orderCountByCustomer", Arrays.asList(
                                group("$customer", sum("orderCount", 1)),
                                project(fields(include("customer", "$_id"), include("orderCount"), include("_id", 0)))
                        ),
                        "totalAmountByCustomer", Arrays.asList(
                                unwind("$products"),
                                group("$customer", sum("totalAmount", new Document("$multiply", Arrays.asList("$products.price", "$products.quantity")))),
                                project(fields(include("customer", "$_id"), include("totalAmount"), include("_id", 0)))
                        )
                )
        ));
        for (Document document : result) {
            System.out.println(document);
        }
    }
}

这波操作,就像同时炒好几道菜,效率直接拉满!

五、总结:毕业成大厨

到这儿,MongoDB 聚合操作的 "十八般武艺" 咱算是学了个七七八八!从基础的筛选、投影,到中级的分组、拆解,再到高阶的跨集合关联、多任务处理,每一招都能在实际项目中大显身手。

不过,光看教程可成不了大厨!赶紧去自己的项目里实操,多试试不同的操作组合。要是遇到 "翻车现场",欢迎来评论区吐槽,咱们一起把这些 "坑" 填平!觉得这篇文章有用的,点赞、收藏、转发三连安排上,让更多小伙伴一起玩转 MongoDB 聚合操作!下次咱们再解锁更多数据库的 "隐藏技能",不见不散!

相关推荐
wkj00120 分钟前
navicate如何设置数据库引擎
数据库·mysql
ladymorgana20 分钟前
【Spring Boot】HikariCP 连接池 YAML 配置详解
spring boot·后端·mysql·连接池·hikaricp
kk在加油3 小时前
Mysql锁机制与优化实践以及MVCC底层原理剖析
数据库·sql·mysql
合作小小程序员小小店4 小时前
web网页开发,在线%ctf管理%系统,基于html,css,webform,asp.net mvc, sqlserver, mysql
mysql·sqlserver·性能优化·asp.net·mvc
JosieBook4 小时前
【Java编程动手学】Java常用工具类
java·python·mysql
hello 早上好4 小时前
MsSql 其他(2)
数据库·mysql
高压锅_12204 小时前
SQLAlchemy数据库连接密码特殊字符处理完全指南
数据库·mysql·django·sqlalchemy
泰勒疯狂展开4 小时前
Java研学-MongoDB(二)
java·mongodb
tan180°12 小时前
MySQL表的操作(3)
linux·数据库·c++·vscode·后端·mysql
DuelCode13 小时前
Windows VMWare Centos Docker部署Springboot 应用实现文件上传返回文件http链接
java·spring boot·mysql·nginx·docker·centos·mybatis