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

相关推荐
菲兹园长2 小时前
MySql(SQL)
数据库·sql·mysql
一只小bit3 小时前
MySQL表的操作:创建—修改—删除流程解析
数据库·mysql·oracle
学编程的小鬼3 小时前
MySQL的快速入门
数据库·mysql
_Power_Y3 小时前
MySql复习及面试题学习
数据库·学习·mysql
学习编程的Kitty3 小时前
MySQL——数据类型和表的操作
数据库·mysql
程序新视界3 小时前
MySQL中,日期、时间与时间戳三种数据类型的区别
数据库·后端·mysql
lang201509284 小时前
MySQL 8.0性能优化终极指南
数据库·mysql·性能优化
苹果醋34 小时前
数据结构其一 线性表
java·运维·spring boot·mysql·nginx
程序新视界4 小时前
MySQL的OR条件查询不走索引及解决方案
数据库·后端·mysql
点灯小铭5 小时前
基于单片机的罐体压力控制器设计与实现
数据库·单片机·mongodb·毕业设计·课程设计