天天看點

Spring data mongodb 聚合,投射,内嵌數組文檔分頁.

盡量别直接用 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      
Spring data mongodb 聚合,投射,内嵌數組文檔分頁.

繼續閱讀