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 聚合操作!下次咱们再解锁更多数据库的 "隐藏技能",不见不散!

相关推荐
emo了小猫3 小时前
Mybatis #{} 和 ${}区别,使用场景,LIKE模糊查询避免SQL注入
数据库·sql·mysql·mybatis
粥里有勺糖12 小时前
用Trae做了个公众号小工具
前端·ai编程·trae
夕颜11112 小时前
让 cursor 教我用 cursor 的隐藏技能
后端·trae
天天摸鱼的java工程师12 小时前
高考放榜夜,系统别崩!聊聊查分系统怎么设计,三张表足以?
java·后端·mysql
exe45213 小时前
jdbc查询mysql数据库时,出现id顺序错误的情况
数据库·mysql
Johny_Zhao14 小时前
阿里云数据库Inventory Hint技术分析
linux·mysql·信息安全·云计算·系统运维
loserkk14 小时前
MySQL InnoDB 5.7 索引失效场景解析:原理与案例
mysql
L.S.V.16 小时前
MYSQL(三)--服务器启动参数与配置
服务器·数据库·mysql
有时间要学习16 小时前
MySQL——视图 && 用户管理 && 语言访问
数据库·mysql
艾露z17 小时前
深度解析Mysql中MVCC的工作机制
java·数据库·后端·mysql