抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

查询场景

mongodb 字段的参数类型不一致不能进行联查的,比如,id默认为ObjectId,另外一张表存的id为String类型,这时候不可以联查;比如存的数据是BigDecimal类型,那么java里聚合查询sum也是不可以的。所以如果表之间,或者构造器构造的字段与数据库的字段类型不一致,那么数据是查不出的。

数据结构

从表1(车牌表)

@Data public class Truck{ @Id protected String id; /** * 运输公司ID(主表id) * * @notExist */ private String transportId; /** * 车牌号 * * @condition * @notExist */ private String truckNo; /** * 创建时间 * * @notView */ private String createTime; /** * 运输单位(关联表的字段) */ private String unitName; /** * 邀请码(关联表的字段) */ private String inviteCode;

}

我只显示关键字段,多余字段不展示,这次处理的是三表联查。上边这个表是从1表,不是主表,把它放在第一个是因为这个表是作为返回使用的。

从表2(邀请码表)

注:邀请人员进入运输单位的表,无需关注我的实际业务。

/** * 邀请码管理 * @access=inviteCode * @parent=appcommon * @parentName=日常业务管理 */ @Data public class InviteCode{ @Id protected String id; /** * 邀请码 * @condition * @notExist */ private String code; /** * 所属运输单位id */ private String belongTransportId;

}

主表(运输单位表)

/** * 运输单位 */ @Data public class TransportUnit{ @Id protected String id; /** * 单位名称 * * @condition * @notExist */ private String unitName; /** * 创建人(邀请人) * * @notView */ private String creator; }

三个表我去了一些没用的内容,保留了三表联查的关键字段。

MongoDB  sql语句实现

从表结构中可以看出,运输单位表作为主表需要关联其他俩个表。从返回表里可以看到我们想要返回内容。

要注意一点的是,为啥以运输单位作为主表,不仅仅是因为主id在这个表中,而且ObjectId转String好转换,反之处理比较麻烦。

db.transportUnit.aggregate([ { $project: { id: { $toString: "$_id" }, unitName: 1, } }, { $lookup: { from: "truck", localField: "id", foreignField: "transportId", as: "truck" } }, { $unwind: "$truck" }, { $lookup: { from: "inviteCode", localField: "id", foreignField: "belongTransportId", as: "inviteCode" } }, { $unwind: "$inviteCode" }, { $project:{ title:1, truck:{ unitName:"$unitName", truckNo:1, code: '$inviteCode.code', transportId:1, creator: 1, createTime: 1, } } }, ]);

解释一下sql:

第一个lookup后使用了unwind将单个Bson拆为Bson数组,这点不可缺少,不然第二层lookup会关联不上。这里使用了project来将ObjectId转为String,当然也是通过这个返回指定字段的。因为之前使用了unwind,最后使用了group再进行一次压缩聚合。

查询结果:

Java实现

public PageInfo<Truck> findAllByLike(Truck truck, int page, int size) throws GenericException { String truckNo = truck.getTruckNo(); String transportName = truck.getTransportName(); Criteria criteria; criteria = Criteria.where("id").not(); if (StringUtils.isNotEmpty(truckNo)){ criteria.and("truckNo").regex(truckNo); } if (StringUtils.isNotEmpty(transportName)){ criteria.and("unitName").regex(transportName); } Aggregation agg = Aggregation.newAggregation( project("id").andExpression("toString(_id)").as("id") .and("unitName").as("unitName"), lookup(Fields.field("truck"),Fields.field("id"),Fields.field("transportId"),Fields.field("truck")), unwind("truck"), lookup("inviteCode","id","belongTransportId","inviteCode"), unwind("inviteCode"), project("unitName") .and("truck.transportId").as("transportId") .and("inviteCode.code").as("inviteCode") .and("truck.creator").as("creator") .and("truck.createTime").as("createTime") .and("truck.truckNo").as("truckNo"), match(criteria), skip((page)*size), limit(size) ); Aggregation agg1 = Aggregation.newAggregation( project("id").andExpression("toString(_id)").as("id") .and("unitName").as("unitName"), lookup(Fields.field("truck"),Fields.field("id"),Fields.field("transportId"),Fields.field("truck")), unwind("truck"), lookup("inviteCode","id","belongTransportId","inviteCode"), unwind("inviteCode"), project("unitName") .and("truck.transportId").as("transportId") .and("inviteCode.code").as("inviteCode") .and("truck.creator").as("creator") .and("truck.createTime").as("createTime") .and("truck.truckNo").as("truckNo"), match(criteria) ); AggregationResults<Truck> results = mongoTemplate.aggregate(agg, "transportUnit", Truck.class); AggregationResults<Truck> results1 = mongoTemplate.aggregate(agg1, "transportUnit", Truck.class); List<Truck> trucks = results.getMappedResults(); List<Truck> mappedResults = results1.getMappedResults(); System.err.println(results.getMappedResults().size()); PageInfo<Truck> pageInfo = new PageInfo<>(trucks); pageInfo.setTotal(mappedResults.size()); return pageInfo; }

这里有个问题,就是聚合查询,分页的情况下无法返回总条数,所以得通过相同的条件,部分也单独查一次总条数。

注意:match查询条件必须放查询联查之后,好比sql  where条件放查询结果之后。

另外一种方式查询

不使用project的方式查询进行类型转换比较麻烦,使用addFields也可以实现。

sql:

db.transportUnit.aggregate([ { $addFields: { id: { $toString: '$_id' } } }, { $lookup: { from: "truck", localField: "id", foreignField: "transportId", as: "truck" } }, { $unwind: "$truck" }, { $lookup: { from: "inviteCode", localField: "id", foreignField: "belongTransportId", as: "inviteCode" } }, { $unwind: "$inviteCode" }, { $project: { title: 1, truck: { unitName: "$unitName", truckNo: 1, code: '$inviteCode.code', transportId: 1, creator: 1, createTime: 1, } } },

]);

查询结果一致,我就不展示了。

可能是我对mongodb不太熟悉,另外一种虽然查出来了但是构造起来有点麻烦,我只实现了个大概。

MongoCollection<Document> collection= mongoTemplate.getCollection("transportUnit"); List<Document> documentArrayList= new ArrayList<>(); collection.aggregate( Arrays.asList( // Aggregates.match(Filters.eq("_id", new ObjectId())), Aggregates.addFields(new Field<>("id",new Document("$toString","$_id"))), Aggregates.lookup("truck","id","transportId","truck"), Aggregates.unwind("$truck"), Aggregates.lookup("inviteCode","id","belongTransportId","inviteCode")) ).forEach((Block<? super Document>) documentArrayList::add); if (documentArrayList.size()>0){ System.err.println(documentArrayList); }

能够写出这篇文章全归功于:https://blog.csdn.net/nyzzht123/article/details/109209847 感谢

评论