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

如何通过Java MongoDB Driver直接获取指定嵌套文档的rights值

问题

我有如下结构的MongoDB文档集合,希望通过Java MongoDB Driver,根据参数_id、groups._id、roles._id,直接从roles数组中获取对应的rights整数值,而不是先查询整个文档再在Java里提取。

文档结构示例

{
  "_id": 1000002,
  "groups": [
    {
      "_id": 1,
      "roles": [
        {
          "rights": 3,
          "_id": 1
        },
        {
          "rights": 7,
          "_id": 2
        },
        {
          "rights": 3,
          "_id": 3
        }
      ]
    }
  ],
  "timestamp": {
    "$date": {
      "$numberLong": "1675267318028"
    }
  },
  "users": [
    {
      "accessProviderId": 1,
      "rights": 1,
      "_id": 4
    },
    {
      "accessProviderId": 1,
      "rights": 3,
      "_id": 5
    }
  ]
}

当前实现代码

目前我通过查询整个AccessListItem对象,再手动提取rights值:

Bson fileFilter = Filters.eq("_id", itemId);
Bson groupFilter = Filters.elemMatch("groups", Document.parse("{_id:"+groupId+"}"));
Bson roleFilter = Filters.elemMatch("groups.roles", Document.parse("{_id:"+role+"}"));

Bson finalFilter = Filters.and(fileFilter, Filters.and(groupFilter,roleFilter));

MongoCollection<AccessListItem> accessListItemMongoCollection = MongoUtils.getAccessCollection(type);
AccessListItem accessListItem = accessListItemMongoCollection.find(finalFilter).first();

解决方案

可以通过MongoDB的聚合管道或精准投影,直接从数据库获取目标rights值,无需加载整个文档。

方法一:聚合管道精准提取(推荐)

通过多步聚合操作,逐层过滤匹配的数组元素,最终提取rights值,适用于所有场景:

import static com.mongodb.client.model.Aggregates.*;
import static com.mongodb.client.model.Filters.*;
import static com.mongodb.client.model.Projections.*;

// 构建聚合管道
List<Bson> pipeline = Arrays.asList(
    // 匹配根文档的_id
    match(eq("_id", itemId)),
    // 过滤出匹配groupId的groups元素,仅保留该元素
    project(fields(
        include("groups"),
        computed("groups", filter("groups", eq("$$this._id", groupId)))
    )),
    // 展开过滤后的groups数组(此时数组仅含一个元素)
    unwind("$groups"),
    // 过滤出匹配roleId的roles元素
    project(fields(
        include("groups.roles"),
        computed("groups.roles", filter("groups.roles", eq("$$this._id", roleId)))
    )),
    // 展开过滤后的roles数组
    unwind("$groups.roles"),
    // 仅保留rights字段
    project(include("groups.roles.rights"))
);

// 执行聚合查询,返回Document类型结果
MongoCollection<Document> collection = MongoUtils.getAccessCollection(type).withDocumentClass(Document.class);
Document result = collection.aggregate(pipeline).first();

// 提取rights整数值
Integer rights = null;
if (result != null) {
    rights = result.getEmbedded(List.of("groups", "roles", "rights"), Integer.class);
}

方法二:精准投影提取(适用于唯一匹配场景)

如果能确保每个根文档下仅有一个匹配的group,每个group下仅有一个匹配的role,可以用投影直接定位:

import static com.mongodb.client.model.Filters.*;
import static com.mongodb.client.model.Projections.*;

// 构建查询过滤器
Bson filter = and(
    eq("_id", itemId),
    eq("groups._id", groupId),
    eq("groups.roles._id", roleId)
);

// 构建投影规则,仅保留匹配的rights相关字段
Bson projection = fields(
    include("groups.roles.rights"),
    filterArray("groups", eq("_id", groupId)),
    filterArray("groups.roles", eq("_id", roleId))
);

// 执行查询并投影
Document result = MongoUtils.getAccessCollection(type).withDocumentClass(Document.class)
    .find(filter)
    .projection(projection)
    .first();

// 提取rights值
Integer rights = null;
if (result != null) {
    List<Document> groups = result.getList("groups", Document.class);
    if (!groups.isEmpty()) {
        List<Document> roles = groups.get(0).getList("roles", Document.class);
        if (!roles.isEmpty()) {
            rights = roles.get(0).getInteger("rights");
        }
    }
}

注意事项

  • 若存在多个匹配的group或role,方法一会返回所有匹配的rights值,需根据业务逻辑处理;方法二则仅返回第一个匹配项。
  • 两种方法都避免了加载整个文档,减少了数据传输量,提升查询效率。

内容的提问来源于stack exchange,提问作者Bojan Stojković

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 19:10:29