在创建树结构的子节点时,Spring Boot与 MongoDB会返回“父节点未找到”

后端开发 2026-07-09

我正在为一个树形结构构建一个Spring Boot API,支持多种存储实现(内存、PostgreSQLMongoDB)。存储实现通过如下属性进行选择:

properties

app.storage=postgres

 or:

app.storage=mongo

API端点

用于创建子节点的端点是:
POST /nodes/{parentId}/children

控制器接收父节点ID的格式为 Long

@Override
public NodeResponse nodesParentIdChildrenPost(Long parentId, NodeRequest nodeRequest) {
    Object child = persistenceService.addChild(parentId, nodeRequest.getName());
    return toNodeResponse(child);
}

PostgreSQL实现

由于实体使用数字ID,这在PostgreSQL上能够正确工作:

@Entity
@Table(name = "nodes")
public class NodeEntity {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    private Long parentId;
}

示例请求:

POST /nodes/1/children

请求体:

{
  "name": "1.1 Caja"
}

MongoDB实现

在MongoDB中,我的文档当前看起来是这样的:

@Document(collection = "nodes")
public class MongoNodeDocument {

    @Id
    private String id;

    private String value;

    private String parentId;
}

仓库方法:

public MongoNodeDocument addChild(String parentId, String value) {
    mongoRepository.findById(parentId)
            .orElseThrow(() ->
                    new RuntimeException("Nodo padre no encontrado: " + parentId));

    MongoNodeDocument child = new MongoNodeDocument(value, parentId);
    return mongoRepository.save(child);
}

持久化服务:

@Override
public Object addChild(Long parentId, String name) {
    return mongoTreeRepository.addChild(String.valueOf(parentId), name);
}

问题

MongoDB生成 _id 值,例如:665f2a0e9d7...

而不是如下所示的数字ID:

1
2
3

因此当我调用: POST /nodes/1/children

MongoDB尝试查找具有 _id = "1" 的文档,并返回:

未找到父节点

疑问

在不改变PostgreSQL与 MongoDB的 REST API合同的前提下,最佳解决方案是什么?

解决方案

你需要解决数据类型不匹配的问题。
将控制器更新为接收String,方式如下:

@PostMapping("/nodes/{parentId}/children")
public NodeResponse createChild(@PathVariable String parentId, @RequestBody NodeRequest req) {
    Object child = persistenceService.addChild(parentId, req.getName());
    return toNodeResponse(child);

在进入JPA仓库之前,更新你的PostgreSQL服务层,通过 Long.parseLong(parentId) 将传入的字符串解析回 Long,同时你的MongoDB层现在也可以直接使用 String 这个原始标识符。

站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章