如何防止 MongoDB 数据库中的递归?

问题描述 投票:0回答:1

我正在制作一个简单的社交媒体平台,并使用 MongoDB 与 Morphia 和 Spring boot。 在我的数据库中,用户有一个他们关注的用户列表,但是如果该列表包含也关注他们的用户,则会创建无限的来回加载每个用户的数据。我怎样才能防止这样的问题?我尝试使用 @Reference(lazy=true) 启用延迟加载,但这没有帮助。

java spring mongodb spring-boot morphia
1个回答
0
投票

对于任何在使用 MongoDB 和 Spring-Boot 时偶然发现这个问题或递归问题的人,解决方案可能是使用 Jackson JSON Views,特别是如果您使用 SpringMVC 的 RestControllers。

按如下方式添加 JsonViews 类应该可以工作:

public class JsonViews {
    public interface Public {}
}

然后,您可以将以下注释添加到您想要包含在任何给定控制器 GET 请求的响应中的字段。

public class Foo {
    @Id @JsonView(JsonViews.Public.class)  String id;

    @DocumentReference(lazy = true) @JsonView(JsonViews.Public.class) Bar someField;
}
public class Bar {
    @Id @JsonView(JsonViews.Public.class) String id;

    @ReadOnlyProperty @DocumentReference(lookup="{ 'bar':?#{#self._id} }") List<Foo> foos;
}
public class FooController {
    @GetMapping @JsonView(JsonViews.Public.class)
    public List<Foo> getAll() { return fooList; }
}

这应该创建以下响应

[
  {
    id: "abc",
    bar: {
      id: "bcd",
    }
  },
  {
    id: "def",
    bar: {
      id: "ghi",
    }
  },
]

要修复在这种情况下返回 Bar 的控制器,您可以创建另一个 JsonViews 样式类 + 接口,但我会将其放置在 Bar 类本身中,作为封装/隔离 Bar 的特定 JsonView 逻辑的一种方式。这会将类更改为以下内容:

public class Foo {
    @Id @JsonView({ JsonViews.Public.class, Bar.PublicView.class }) String id;

    @DocumentReference(lazy = true) @JsonView(JsonViews.Public.class) Bar someField;
}
public class Bar {
    @Id @JsonView({ JsonViews.Public.class, PublicView.class }) String id;

    @ReadOnlyProperty @DocumentReference(lookup="{ 'bar':?#{#self._id} }")
    @JsonView(PublicView.class) List<Foo> foos;
    public interface PublicView {}
}

然后在你的控制器中你可以这样做:

public class BarController {
    @GetMapping @JsonView(Bar.PublicView.class)
    public List<Bar> getAll() { return barList; }
}

这应该创建以下响应

[
  {
    id: "cba",
    foos: [
      {
        id: "fed"
      },
      {
        id: "ihg"
      }
    ]
  },
  {
    id: "edc",
    foos: [
      {
        id: "xyz"
      },
      {
        id: "zyx"
      }
    ]
  }
]

可能的潜在问题

由于 SpringMVC 的 RestController 需要将数据解析为响应正文的 JSON 字符串,因此 Spring 使用的 Jackson JSON Serializer 默认情况下将解析 Lazy DocumentReference。当然,如果您有循环引用,这将导致无限递归(如果您有一个属性指向每个类中的另一个模型,则可能是这种情况)

您可以查看 Spring-Boot 的 Jackson JSONViews 页面以获取更多信息。

© www.soinside.com 2019 - 2024. All rights reserved.