You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SpringBoot中MongoRepository聚合查询$Project字段排除失效问题

Spring Boot MongoRepository聚合查询中$project无法排除嵌套字段的解决方案

问题场景

在Spring Boot应用的MongoRepository中编写了如下聚合查询,意图关联t_user集合并排除contact.password和contact.salt字段,但执行后这两个字段仅被设为null而非完全移除;相同语句在Mongo控制台执行时则能成功排除字段。

聚合查询代码:

@Aggregation({
            "{$match:{createUid: ?0}}",
            "{$lookup: {from: 't_user',localField: 'contactUid',foreignField:'_id',as: 'contact'}}",
            "{$addFields: {contact:{$arrayElemAt: ['$contact',0]} }}",
            "{$project: { 'contact.password': 0,'contact.salt': 0}}",
    })
List<HashMap> searchSentAddContacts(ObjectId createUid);

集合结构:
t_add_contacts:

[
  {
    "_id": {"$oid": "66ef75795e8146631d0658bc"},
    "_class": "org.tzx.xim.entity.AddContactsEntity",
    "addType": 0,
    "contactUid": {"$oid": "66ef75505e8146631d0658bb"},
    "createTime": {"$date": "2024-09-22T01:40:09.665Z"},
    "createUid": {"$oid": "66ef75425e8146631d0658ba"},
    "updateTime": {"$date": "2024-09-22T01:40:09.665Z"}
  }
]

t_user:

[
  {
    "_id": {"$oid": "66ef75425e8146631d0658ba"},
    "_class": "org.tzx.xim.entity.UserEntity",
    "createTime": {"$date": "2024-09-22T01:39:14.569Z"},
    "loginName": "user1",
    "nickName": "haha1",
    "password": "123456",
    "salt": "awsddqwdqwd",
    "updateTime": {"$date": "2024-09-22T01:39:14.569Z"}
  }
]

解决方案

方案1:在$lookup阶段直接过滤字段(推荐)

将字段过滤逻辑提前到$lookup的pipeline中,避免后续冗余处理,同时提升查询效率:

@Aggregation({
    "{$match:{createUid: ?0}}",
    "{$lookup: {from: 't_user',localField: 'contactUid',foreignField:'_id',as: 'contact', pipeline: [{$project: {password: 0, salt: 0}}]}}",
    "{$addFields: {contact:{$arrayElemAt: ['$contact',0]} }}"
})
List<HashMap> searchSentAddContacts(ObjectId createUid);

此方式在关联t_user时就直接排除了不需要的字段,最终结果中不会出现password和salt。

方案2:使用自定义DTO接收结果

创建仅包含所需字段的DTO类,Spring Data MongoDB会自动忽略无对应映射的字段:

// 主DTO类
public class AddContactWithUserDTO {
    private ObjectId id;
    private Integer addType;
    private ObjectId contactUid;
    private Date createTime;
    private ObjectId createUid;
    private Date updateTime;
    private UserContactDTO contact;

    // Getters & Setters

    // 嵌套的用户信息DTO
    public static class UserContactDTO {
        private ObjectId id;
        private Date createTime;
        private String loginName;
        private String nickName;
        private Date updateTime;

        // Getters & Setters
    }
}

修改Repository方法的返回类型:

List<AddContactWithUserDTO> searchSentAddContacts(ObjectId createUid);

即使聚合结果中存在password和salt,由于DTO中未定义对应字段,不会被映射到返回结果里。

方案3:在$project中明确指定所有需保留的字段

替代仅排除字段的写法,直接列出所有需要保留的字段,确保不需要的字段被完全移除:

@Aggregation({
    "{$match:{createUid: ?0}}",
    "{$lookup: {from: 't_user',localField: 'contactUid',foreignField:'_id',as: 'contact'}}",
    "{$addFields: {contact:{$arrayElemAt: ['$contact',0]} }}",
    "{$project: { 
        _id: 1,
        addType: 1,
        contactUid: 1,
        createTime: 1,
        createUid: 1,
        updateTime: 1,
        'contact._id': 1,
        'contact.createTime': 1,
        'contact.loginName': 1,
        'contact.nickName': 1,
        'contact.updateTime': 1
    }}"
})
List<HashMap> searchSentAddContacts(ObjectId createUid);

内容的提问来源于stack exchange,提问作者user27406708

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 06:23:13