盡量別直接用 DBObject ,Spring data mongodb 的api 本來就沒什么多大用處,如果還直接用 DBObject 那么還需要自己去解析結果,說動做個對象映射,累不累
Spring data mongodb 唯一好處就是,不需要自己decode encode,其他別的幾乎也沒了
DBObject project = new BasicDBObject("$project", new BasicDBObject("_id", 1) .append("..", "$..").append("..", 1) .append("..", 1).append("..", 1) .append("..", 1).append("..", 1) .append("..", 1).append("..", 1) .append("..", 1).append("..", 1) .append("..", 1).append("..", 1) .append("..", 1).append("..", 1) .append("..", 1).append("..", 1) .append("..", 1).append("..", 1) .append("..", 1).append("..", 1) .append("..", 1)); query.add(project); query.add(new BasicDBObject("$unwind", "$...")); query.add(new BasicDBObject("$skip",...)); query.add(new BasicDBObject("$limit",...)); AggregationOutput aggregationOutput = mongoTemplate.getCollection("...").aggregate(query);
以下使用Spring data mongodb 做聚合,內嵌文檔分頁,訂單 - 明細 一對多的例子
package com.example.mongo.entity; import lombok.Data; import lombok.experimental.Accessors; import org.bson.types.ObjectId; import org.springframework.data.annotation.Id; import java.io.Serializable; import java.util.List; /** * Created by laizhenwei on 2017/11/9 */ @Data @Accessors(chain = true) public class Order implements Serializable { private static final long serialVersionUID = 4738576111790390042L; @Id private ObjectId objectId; private List<Detail> details; /** * 企業編號 */ private String compyCode; /** * 訂單號 */ private String orderNo; /** * 用戶名 */ private String userName; }
明細實體
package com.example.mongo.entity; import lombok.Data; import lombok.experimental.Accessors; import org.bson.types.ObjectId; import java.io.Serializable; import java.math.BigDecimal; /** * Created by laizhenwei on 2017/11/9 */ @Data @Accessors(chain = true) public class Detail implements Serializable { private static final long serialVersionUID = 942116549431791887L; private ObjectId id; /** * 商品名稱 */ private String productName; /** * 商品數量 */ private Long itemQty; /** * 單價 */ private BigDecimal price; }
Junit
package com.example.mongo.Repository; import com.example.mongo.entity.Detail; import com.example.mongo.entity.Order; import com.mongodb.BasicDBList; import com.mongodb.DBObject; import lombok.Data; import org.bson.types.ObjectId; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.data.annotation.Id; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.aggregation.Aggregation; import org.springframework.data.mongodb.core.aggregation.AggregationOperation; import org.springframework.test.context.junit4.SpringRunner; import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; import java.util.Optional; import static org.springframework.data.mongodb.core.aggregation.Aggregation.*; import static org.springframework.data.mongodb.core.aggregation.Aggregation.limit; import static org.springframework.data.mongodb.core.query.Criteria.where; /** * Created by laizhenwei on 2017/11/9 */ @RunWith(SpringRunner.class) @SpringBootTest public class OrderTests { @Autowired private OrderRepository orderRepository; @Autowired private MongoTemplate mongoTemplate; private String[] compyCode = {"123123", "456456", "789789"}; private String[] userNames = {"Athos", "Peter", "Nero", "Gavin", "Carter"}; /** * 造一點數據 */ @Test public void save() { List<Order> orders = new ArrayList<>(200); for (int i = 0; i < 200; i++) { List<Detail> details = new ArrayList<>(3); for (int j = 0; j < 3; j++) { Detail detail = new Detail(); detail.setId(new ObjectId()); detail.setItemQty((long) (i + 1)); detail.setProductName("產品" + i + "_" + j); detail.setPrice(new BigDecimal(10 + i)); details.add(detail); } Order order = new Order(); order.setCompyCode(compyCode[i % 3]); order.setUserName(userNames[i % 5]); order.setOrderNo(String.valueOf(i)); order.setDetails(details); orders.add(order); } orderRepository.insert(orders); } /** * 內嵌文檔分頁查詢 */ @Test public void pageQuery() { Detail detailDto = new Detail(); detailDto.setProductName("產品19_0"); List<AggregationOperation> commonOperations = new ArrayList<>(9); commonOperations.add(project("objectId", "details", "compyCode", "orderNo", "userName").and("details").as("detail")); Optional.ofNullable(detailDto.getProductName()).ifPresent(s -> commonOperations.add(match(where("details.productName").is(detailDto.getProductName())))); commonOperations.add(unwind("detail")); List<AggregationOperation> pageOperations = new ArrayList<>(commonOperations); pageOperations.add(skip(1l)); pageOperations.add(limit(10)); List<AggregationOperation> totalAggOperation = new ArrayList<>(commonOperations); totalAggOperation.add(group().count().as("total")); List<DetailVo> results = mongoTemplate.aggregate(Aggregation.newAggregation(Order.class,pageOperations), Order.class, DetailVo.class).getMappedResults(); System.out.println(results.size()); DBObject rawResults = mongoTemplate.aggregate(Aggregation.newAggregation(Order.class,totalAggOperation), String.class).getRawResults(); BasicDBList result = (BasicDBList)rawResults.get("result"); long total = result.isEmpty() ? 0 : Long.parseLong(((DBObject)result.get(0)).get("total").toString()); System.out.println("total:" + total); } /** * 結果實體 */ @Data private static class DetailVo{ @Id private ObjectId orderId; private Detail detail; private String compyCode; private String orderNo; private String userName; } }
logback 打開 方便觀察
<Logger name="org.mongodb.driver" level="debug" />
<logger name="org.springframework.data.mongodb.core.MongoTemplate" level="debug" />
控制台輸出,只取重點,因為skip 了一個,所以結果只有2個,總數量是3個
13:45:31.740 logback [main] DEBUG o.s.data.mongodb.core.MongoTemplate - Executing aggregation: { "aggregate" : "order" , "pipeline" : [ { "$project" : { "objectId" : "$_id" , "details" : 1 , "compyCode" : 1 , "orderNo" : 1 , "userName" : 1 , "detail" : "$details"}} , { "$match" : { "details.productName" : "產品19_0"}} , { "$unwind" : "$detail"} , { "$skip" : 1} , { "$limit" : 10}]} 13:45:31.743 logback [main] DEBUG o.s.data.mongodb.core.MongoDbUtils - Getting Mongo Database name=[e9] 13:45:31.752 logback [main] INFO org.mongodb.driver.connection - Opened connection [connectionId{localValue:2}] to 192.168.1.9:27023 13:45:31.756 logback [main] DEBUG org.mongodb.driver.protocol.command - Sending command {aggregate : BsonString{value='order'}} to database e9 on connection [connectionId{localValue:2}] to server 192.168.1.9:27023 13:45:31.759 logback [main] DEBUG org.mongodb.driver.protocol.command - Command execution completed 13:45:31.765 logback [main] DEBUG o.s.d.m.c.i.MongoPersistentEntityIndexCreator - Analyzing class class com.example.mongo.Repository.OrderTests$DetailVo for index information. 2 13:45:31.780 logback [main] DEBUG o.s.data.mongodb.core.MongoTemplate - Executing aggregation: { "aggregate" : "order" , "pipeline" : [ { "$project" : { "objectId" : "$_id" , "details" : 1 , "compyCode" : 1 , "orderNo" : 1 , "userName" : 1 , "detail" : "$details"}} , { "$match" : { "details.productName" : "產品19_0"}} , { "$unwind" : "$detail"} , { "$group" : { "_id" : null , "total" : { "$sum" : 1}}}]} 13:45:31.780 logback [main] DEBUG o.s.data.mongodb.core.MongoDbUtils - Getting Mongo Database name=[e9] 13:45:31.780 logback [main] DEBUG org.mongodb.driver.protocol.command - Sending command {aggregate : BsonString{value='order'}} to database e9 on connection [connectionId{localValue:2}] to server 192.168.1.9:27023 13:45:31.782 logback [main] DEBUG org.mongodb.driver.protocol.command - Command execution completed total:3