mongoDB聚合查询实现多表联查,类型转换,返回指定参数。

查询场景

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,

  1. 第一个lookup后使用了unwind将单个Bson拆为Bson数组,这点不可缺少,不然第二层lookup会关联不上。
  2. 这里使用了project来将ObjectId转为String,当然也是通过这个返回指定字段的。
  3. 因为之前使用了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

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
MongoDB中,聚合查询是用于对集合中的文档进行多个操作并返回计算结果的操作。常见的MongoDB聚合操作包括: - `$match`:用于筛选满足指定条件的文档。 - `$group`:用于根据指定字段对文档进行分组,并可以对分组后的文档进行一些聚合操作,如求和、计数等。 - `$sort`:用于对文档进行排序。 - `$project`:用于选择指定字段,并可以进行一些达式的计算和转换。 - `$limit`:用于限制返回的文档数量。 - `$sum`:用于对指定字段进行求和计算。 - `$count`:用于统计文档数量。 - `$lookup`:用于对多个集合进行关联查询。 例如,以下是一个使用聚合查询的示例语法: ``` db.collection.aggregate([ { $match: { field: value } }, { $group: { _id: "$field", total: { $sum: "$field2" } } }, { $sort: { total: -1 } }, { $limit: 10 } ]) ``` 以上示例中,首先使用`$match`操作筛选出满足条件的文档,然后使用`$group`操作按照指定字段进行分组,并使用`$sum`操作对分组后的文档中的某个字段进行求和计算,接着使用`$sort`操作对求和结果进行排序,最后使用`$limit`操作限制返回的文档数量。 需要注意的是,具体的聚合查询语法可能会根据具体的需求而有所不同,上述示例仅供参考。在实际使用中,需要根据具体的字段和操作来构建合适的聚合查询语句。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [【详细教程】一文参透MongoDB聚合查询](https://blog.csdn.net/bxg_kyjgs/article/details/125803527)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT0_1"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

答 案

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值