SpringData整合MongoDB

  • Post author:
  • Post category:其他


项目地址:

https://gitee.com/Anntly/mongo-crud


常见的 增删改查、地理位置、嵌套文档、聚合函数



新建项目

image.png

image.png

修改 application.yml 添加 mongodb数据源信息

spring:
  data:
    mongodb:
      uri: mongodb://jboom:123456@127.0.0.1:27017/logistics
      auto-index-creation: true



案例代码

以物流订单为例(非真实项目设计)



LogisticsOrder 物流订单

/**
 * 物流订单
 */
@Data
@Document("logistics_order")
@ToString
public class LogisticsOrder {

    /**
     * 物流订单id
     */
    @MongoId
    @AutoId
    private Long orderId;

    /**
     * 用户id
     */
    private Long userId;

    /**
     * 订单价格
     */
    private BigDecimal price;

    /**
     * 订单总重
     */
    private BigDecimal weight;

    /**
     * 目的地
     */
    private GeoJsonPoint to;

    /**
     * 出发地
     */
    private GeoJsonPoint from;

    /**
     * 当前位置
     */
    @GeoSpatialIndexed(type = GeoSpatialIndexType.GEO_2DSPHERE,useGeneratedName = true)
    private GeoJsonPoint location;

    /**
     * 距离
     */
    private transient Double distance;

    /**
     * 住址信息
     */
    private Address address;

    /**
     * 运送物品
     */
    private List<OrderItem> items;

    /**
     * 0 已发货
     * 1 待收件
     * 2 已揽收
     * 3 运输中
     * 4 配送中
     * 5 已签收
     */
    private Integer status;

    /**
     * 发出时间
     */
    @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
    private LocalDateTime sendTime;

    /**
     * 发出时间
     */
    @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
    private LocalDateTime receiveTime;

    /**
     * 操作者
     */
    private String operator;

    /**
     * 操作时间
     */
    @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
    private LocalDateTime operateTime;

    /**
     * 备注
     */
    private String remark;
}



OrderItem 订单货物

/**
 * 物流货物
 */
@Data
@ToString
public class OrderItem {

    /**
     * 货物id
     */
    private Long itemId;

    /**
     * 货物信息
     */
    private String info;

    /**
     * 商品毛重
     */
    private BigDecimal weight;

    /**
     * 商品价格
     */
    private BigDecimal price;

}



Address 地址信息

@Data
@ToString
public class Address {

    private String province;

    private String city;

    private String counties;

    private String detail;

    private String postCode;
}



CRUD

案例直接使用的MongoTemplate

@Resource
private MongoTemplate mongoTemplate;



新增订单

新增很简单

/**
 * 新增订单
 *
 * @param order
 * @return
 */
public Long addOrder(LogisticsOrder order) {
    return mongoTemplate.insert(order).getOrderId();
}



查询订单,同时返回距离当前位置的距离

使用 NearQuery 包一层用于返回 GeoResult 获取 distance

/**
 * mongodb一个集合最好只设计一个地理索引,多个会冲突
 * 查询指定经纬度与数据的距离
 *
 * @param orderId
 * @param longitude 收货地精度
 * @param latitude  收货地纬度  -- 用于计算距离
 * @return
 */
public LogisticsOrder getOrder(Long orderId, double longitude, double latitude) {
    Criteria criteria = Criteria.where("_id").is(orderId);
    Query query = new Query(criteria);
    NearQuery nearQuery = NearQuery
            .near(new GeoJsonPoint(longitude, latitude), Metrics.MILES)
            .query(query);
    GeoResults<LogisticsOrder> results = mongoTemplate.geoNear(nearQuery, LogisticsOrder.class);
    for (GeoResult<LogisticsOrder> result : results) {
        LogisticsOrder content = result.getContent();
        double distance = result.getDistance().getValue();
        content.setDistance(distance);
    }
    // 处理距离
    return results.getContent().get(0).getContent();
}



查询坐标范围内的订单

/**
 * 获取用户 range 公里范围(km)内的订单
 *
 * @param userId
 * @param longitude
 * @param latitude
 * @param range
 * @return
 */
public List<LogisticsOrder> getUserRangeOrder(Long userId, double longitude, double latitude, Integer range) {
    GeoJsonPoint point = new GeoJsonPoint(longitude, latitude);
    Distance distance = new Distance(range, Metrics.KILOMETERS);
    // 圆圈范围内
    Circle circle = new Circle(point, distance);
    Criteria criteria = Criteria.where("userId").is(userId)
            .and("location").withinSphere(circle);
    Query query = new Query(criteria);
    return mongoTemplate.find(query, LogisticsOrder.class);
}



修改订单

/**
 * 操作员操作,发货、揽收、配送、签收等操作
 *
 * @param orderId
 * @param operator
 * @param longitude
 * @param latitude
 * @param status
 * @return
 */
public boolean operateOrder(Long orderId, String operator, double longitude, double latitude, Integer status) {
    Criteria criteria = Criteria.where("orderId").is(orderId);
    Query query = new Query(criteria);
    Update update = new Update().set("operator", operator)
            .set("location", new GeoJsonPoint(longitude, latitude))
            .set("status", status);
    UpdateResult result = mongoTemplate.updateFirst(query, update, LogisticsOrder.class);
    return result.getMatchedCount() != 0;
}



修改地址信息,嵌套子文档

/**
 * 修改收货地址
 * 修改嵌套子文档字段
 *
 * @param orderId
 * @return
 */
public boolean modifyReceiveAddress(Long orderId, String province, String city,
                                    String counties, String detail, String postCode) {
    Criteria criteria = Criteria.where("_id").is(orderId);
    Query query = new Query(criteria);
    Update update = new Update();
    Optional.ofNullable(province).ifPresent(p -> update.set("address.province", p));
    Optional.ofNullable(city).ifPresent(c -> update.set("address.city", c));
    Optional.ofNullable(counties).ifPresent(c -> update.set("address.counties", c));
    Optional.ofNullable(detail).ifPresent(d -> update.set("address.detail", d));
    Optional.ofNullable(postCode).ifPresent(p -> update.set("address.postCode", p));
    return mongoTemplate.updateFirst(query, update, LogisticsOrder.class).getMatchedCount() > 0;
}



修改货物信息,嵌套子文档(数组)

/**
 * 更新货物信息
 * 更新嵌套数组对象字段信息
 *
 * @param orderId
 * @param itemId
 * @param weight
 * @param price
 * @param info
 * @return
 */
public boolean modifyItem(Long orderId, Long itemId, BigDecimal weight, BigDecimal price, String info) {
    Criteria criteria = Criteria.where("_id").is(orderId)
            .and("items.itemId").is(itemId);
    Query query = new Query(criteria);
    Update update = new Update();
    Optional.ofNullable(weight).ifPresent(w -> update.set("items.$.weight", w));
    Optional.ofNullable(price).ifPresent(p -> update.set("items.$.price", p));
    Optional.ofNullable(info).ifPresent(i -> update.set("items.$.info", i));

    UpdateResult result = mongoTemplate.updateFirst(query, update, LogisticsOrder.class);
    return result.getMatchedCount() != 0;
}



新增货物,嵌套子文档(数组)

/**
 * 添加货物
 * 嵌套数组添加元素
 *
 * @param orderId
 * @param item
 * @return
 */
public boolean addItem(Long orderId, OrderItem item) {
    Criteria criteria = Criteria.where("_id").is(orderId);
    Query query = new Query(criteria);
    Update update = new Update();
    // 不重复就用addToSet
    update.push("items", item);
    UpdateResult result = mongoTemplate.updateFirst(query, update, LogisticsOrder.class);
    return result.getMatchedCount() != 0;
}



删除货物,嵌套子文档(数组)

/**
 * 清除货物
 * 嵌套数组删除元素
 *
 * @param orderId
 * @param itemId
 * @return
 */
public boolean removeItem(Long orderId, Long itemId) {
    Criteria criteria = Criteria.where("_id").is(orderId);
    Query query = new Query(criteria);
    BasicDBObject dbObject = new BasicDBObject();
    dbObject.put("itemId", itemId);
    Update update = new Update();
    update.pull("items", dbObject);
    UpdateResult result = mongoTemplate.updateFirst(query, update, LogisticsOrder.class);
    return result.getMatchedCount() != 0;
}



统计用户不同状态的订单数,聚合

/**
 * 统计用户每个状态的订单数
 *
 * @param userId
 * @return
 */
public void userStatusOrderNum(Long userId) {
    AggregationOperation match = Aggregation.match(Criteria.where("userId").is(userId));
    AggregationOperation group = Aggregation.group("status").count().as("orderNum");
    Aggregation aggregation = Aggregation.newAggregation(match, group);
    AggregationResults<Map> aggregate = mongoTemplate.aggregate(aggregation, LogisticsOrder.class, Map.class);
    for (Map map : aggregate) {
        System.out.println(map);
    }
}



版权声明:本文为ticktak原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。