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:食材拆解师

u n w i n d 就像把一捆菜拆开的"拆包大师",专门对付数组类型的数据!在上面 unwind 就像把一捆菜拆开的 "拆包大师",专门对付数组类型的数据!在上面 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 聚合操作!下次咱们再解锁更多数据库的 "隐藏技能",不见不散!

相关推荐
yuezhilangniao3 分钟前
xtr备份prepare到底变化了啥
mysql
yyk的萌5 分钟前
创建属于自己的mysql的mcp
mysql·adb·ai·mcp
流烟默5 分钟前
腾讯云Centos7.6使用yum安装MySQL8
mysql·centos·腾讯云
仙俊红10 分钟前
如何优化 MySQL 深分页 SQL
android·sql·mysql
超梦dasgg42 分钟前
工作中 MySQL 读写分离主从延迟:成因、影响、落地方案、生产实战处理
数据库·mysql
疯狂热爱代码的00后1 小时前
入门必看! MySQL增删改查全套示例SQL 直接复制运行
mysql
huipeng9261 小时前
企业级微服务开发实战(二):微服务基础设施搭建与中间件部署
java·redis·mysql·spring cloud·微服务·nacos·rabbitmq
可乐ea2 小时前
【知识获取与分享社区项目 | 项目日记第 24 天】终章总结:从认证、发布、计数、Feed、搜索到 RAG:完整复盘一个知识社区后端系统
java·spring boot·redis·mysql·elasticsearch·ai·kafka
小小编程路2 小时前
MySQL9.0|融合向量的新一代关系数据库安装配置教程
mysql
不会就选b11 小时前
MySQL之视图
数据库·mysql