映射框架不必存储嵌入在文档中的子对象。 您也可以单独存储它们,并使用 来引用该文档。 当对象从MongoDB加载时,这些引用会急切地解析,以便您返回一个映射对象,该对象看起来与嵌入在顶级文档中的存储对象相同。DBRefSpring中文文档

下面的示例使用 DBRef 来引用独立于引用它的对象而存在的特定文档(为简洁起见,这两个类都以内联方式显示):Spring中文文档

@Document
public class Account {

  @Id
  private ObjectId id;
  private Float total;
}

@Document
public class Person {

  @Id
  private ObjectId id;
  @Indexed
  private Integer ssn;
  @DBRef
  private List<Account> accounts;
}

您不需要使用或类似的机制,因为对象列表会告诉映射框架您想要一对多关系。 当对象存储在 MongoDB 中时,有一个 DBRefs 列表,而不是对象本身。 在加载 s 的集合时,建议将集合类型中保存的引用限制为特定的 MongoDB 集合。 这允许批量加载所有引用,而指向不同MongoDB集合的引用需要逐个解析。@OneToManyAccountDBRefSpring中文文档

映射框架不处理级联保存。 如果更改对象引用的对象,则必须单独保存该对象。 调用对象不会自动将对象保存在属性中。AccountPersonAccountsavePersonAccountaccounts

DBRef也可以懒惰地解决。 在这种情况下,实际或引用在首次访问属性时解析。 使用 的属性来指定这一点。 也被定义为延迟加载并用作构造函数参数的必需属性也使用延迟加载代理进行修饰,以确保对数据库和网络施加尽可能小的压力。ObjectCollectionlazy@DBRefDBRefSpring中文文档

延迟加载可能很难调试。 确保工具不会意外触发代理解析,例如调用或某些内联调试呈现调用属性 getter 来触发代理解析。 请考虑启用跟踪日志记录,以便深入了解解决方案。DBReftoString()org.springframework.data.mongodb.core.convert.DefaultDbRefResolverDBRef
延迟加载可能需要类代理,而类代理又可能需要访问未打开的 jdk 内部,从 Java 16+ 开始,这是由于 JEP 396:默认情况下强封装 JDK 内部。 对于这些情况,请考虑回退到接口类型(例如,从切换到 )或提供所需的参数。ArrayListList--add-opens
映射框架不处理级联保存。 如果更改对象引用的对象,则必须单独保存该对象。 调用对象不会自动将对象保存在属性中。AccountPersonAccountsavePersonAccountaccounts
延迟加载可能很难调试。 确保工具不会意外触发代理解析,例如调用或某些内联调试呈现调用属性 getter 来触发代理解析。 请考虑启用跟踪日志记录,以便深入了解解决方案。DBReftoString()org.springframework.data.mongodb.core.convert.DefaultDbRefResolverDBRef
延迟加载可能需要类代理,而类代理又可能需要访问未打开的 jdk 内部,从 Java 16+ 开始,这是由于 JEP 396:默认情况下强封装 JDK 内部。 对于这些情况,请考虑回退到接口类型(例如,从切换到 )或提供所需的参数。ArrayListList--add-opens

使用文档引用

使用提供了一种在MongoDB中引用实体的灵活方式。 虽然目标与使用 DBRefs 时相同,但存储表示形式不同。 解析为具有MongoDB参考文档中概述的固定结构的文档。
文档引用,不要遵循特定的格式。 它们可以是任何东西,单个值,整个文档,基本上是可以存储在MongoDB中的所有内容。 默认情况下,映射图层将使用引用的实体 id 值进行存储和检索,如以下示例所示。
@DocumentReferenceDBRefSpring中文文档

@Document
class Account {

  @Id
  String id;
  Float total;
}

@Document
class Person {

  @Id
  String id;

  @DocumentReference                                   (1)
  List<Account> accounts;
}
Account account = …

template.insert(account);                               (2)

template.update(Person.class)
  .matching(where("id").is(…))
  .apply(new Update().push("accounts").value(account)) (3)
  .first();
{
  "_id" : …,
  "accounts" : [ "6509b9e" … ]                        (4)
}
1 标记要引用的值的集合。Account
2 映射框架不处理级联保存,因此请确保单独保留引用的实体。
3 添加对现有实体的引用。
4 引用的实体表示为其值的数组。Account_id

上面的示例使用基于 -的 fetch 查询 () 进行数据检索,并急切地解析链接实体。 可以使用以下属性更改分辨率默认值(如下所列)_id{ '_id' : ?#{#target} }@DocumentReferenceSpring中文文档

表 1.@DocumentReference默认值
属性 描述 违约

dbSpring中文文档

集合查找的目标数据库名称。Spring中文文档

MongoDatabaseFactory.getMongoDatabase()Spring中文文档

collectionSpring中文文档

目标集合名称。Spring中文文档

带批注的属性的域类型,分别是值类型(如果是 like 或属性)、集合名称。CollectionMapSpring中文文档

lookupSpring中文文档

单个文档查找查询通过 SpEL 表达式评估占位符,用作给定源值的标记。 like 或 properties 通过运算符组合单个查找。#targetCollectionMap$orSpring中文文档

使用加载的源值的基于字段的查询 ()。_id{ '_id' : ?#{#target} }Spring中文文档

sortSpring中文文档

用于在服务器端对结果文档进行排序。Spring中文文档

默认情况下无。 类似属性的结果顺序会根据已使用的查找查询在尽力而为的基础上恢复。CollectionSpring中文文档

lazySpring中文文档

如果设置为值,则在首次访问属性时会延迟解析。trueSpring中文文档

默认情况下急切地解析属性。Spring中文文档

延迟加载可能需要类代理,而类代理又可能需要访问未打开的 jdk 内部,从 Java 16+ 开始,这是由于 JEP 396:默认情况下强封装 JDK 内部。 对于这些情况,请考虑回退到接口类型(例如,从切换到 )或提供所需的参数。ArrayListList--add-opens

@DocumentReference(lookup)允许定义可能与字段不同的筛选器查询,因此提供了一种灵活的方式来定义实体之间的引用,如下面的示例所示,其中 of a book 由其首字母缩略词引用,而不是 internal ._idPublisheridSpring中文文档

@Document
class Book {

  @Id
  ObjectId id;
  String title;
  List<String> author;

  @Field("publisher_ac")
  @DocumentReference(lookup = "{ 'acronym' : ?#{#target} }") (1)
  Publisher publisher;
}

@Document
class Publisher {

  @Id
  ObjectId id;
  String acronym;                                            (1)
  String name;

  @DocumentReference(lazy = true)                            (2)
  List<Book> books;

}
Book公文
{
  "_id" : 9a48e32,
  "title" : "The Warded Man",
  "author" : ["Peter V. Brett"],
  "publisher_ac" : "DR"
}
Publisher公文
{
  "_id" : 1a23e45,
  "acronym" : "DR",
  "name" : "Del Rey",
  …
}
1 使用该字段查询集合中的实体。acronymPublisher
2 延迟加载回对集合的引用。Book

上面的代码片段显示了使用自定义引用对象时事物的阅读方面。 写作需要一些额外的设置,因为映射信息没有表示来源。 映射图层需要在目标文档和 之间注册 a,如下所示:#targetConverterDocumentPointerSpring中文文档

@WritingConverter
class PublisherReferenceConverter implements Converter<Publisher, DocumentPointer<String>> {

	@Override
	public DocumentPointer<String> convert(Publisher source) {
		return () -> source.getAcronym();
	}
}

如果未提供转换器,则可以根据给定的查找查询计算目标参考文档。 在这种情况下,将评估关联目标属性,如以下示例所示。DocumentPointerSpring中文文档

@Document
class Book {

  @Id
  ObjectId id;
  String title;
  List<String> author;

  @DocumentReference(lookup = "{ 'acronym' : ?#{acc} }") (1) (2)
  Publisher publisher;
}

@Document
class Publisher {

  @Id
  ObjectId id;
  String acronym;                                        (1)
  String name;

  // ...
}
{
  "_id" : 9a48e32,
  "title" : "The Warded Man",
  "author" : ["Peter V. Brett"],
  "publisher" : {
    "acc" : "DOC"
  }
}
1 使用该字段查询集合中的实体。acronymPublisher
2 查找查询的字段值占位符(如 )用于形成参考文档。acc

也可以使用 和 的组合对关系样式的一对多引用进行建模。 此方法允许链接类型不将链接值存储在所属文档中,而是存储在引用文档上,如下面的示例所示。@ReadonlyProperty@DocumentReferenceSpring中文文档

@Document
class Book {

  @Id
  ObjectId id;
  String title;
  List<String> author;

  ObjectId publisherId;                                        (1)
}

@Document
class Publisher {

  @Id
  ObjectId id;
  String acronym;
  String name;

  @ReadOnlyProperty                                            (2)
  @DocumentReference(lookup="{'publisherId':?#{#self._id} }")  (3)
  List<Book> books;
}
Book公文
{
  "_id" : 9a48e32,
  "title" : "The Warded Man",
  "author" : ["Peter V. Brett"],
  "publisherId" : 8cfb002
}
Publisher公文
{
  "_id" : 8cfb002,
  "acronym" : "DR",
  "name" : "Del Rey"
}
1 通过在文档中存储 来设置从(引用)到(所有者)的链接。BookPublisherPublisher.idBook
2 将保存引用的属性标记为只读。 这样可以防止在文档中存储对单个 s 的引用。BookPublisher
3 使用变量访问文档中的值,并在此检索中使用匹配 。#selfPublisherBookspublisherId

有了上述所有条件,就可以对实体之间的各种关联进行建模。 看看下面的非详尽示例列表,以了解什么是可能的。Spring中文文档

例 1.使用 id 字段的简单文档引用
class Entity {
  @DocumentReference
  ReferencedObject ref;
}
// entity
{
  "_id" : "8cfb002",
  "ref" : "9a48e32" (1)
}

// referenced object
{
  "_id" : "9a48e32" (1)
}
1 MongoDB简单类型可以直接使用,无需进一步配置。
例 2.使用具有显式查找查询的 id 字段的简单文档引用
class Entity {
  @DocumentReference(lookup = "{ '_id' : '?#{#target}' }") (1)
  ReferencedObject ref;
}
// entity
{
  "_id" : "8cfb002",
  "ref" : "9a48e32"                                        (1)
}

// referenced object
{
  "_id" : "9a48e32"
}
1 target 定义引用值本身。
例 3.Document Reference 提取查找查询的字段refKey
class Entity {
  @DocumentReference(lookup = "{ '_id' : '?#{refKey}' }")  (1) (2)
  private ReferencedObject ref;
}
@WritingConverter
class ToDocumentPointerConverter implements Converter<ReferencedObject, DocumentPointer<Document>> {
	public DocumentPointer<Document> convert(ReferencedObject source) {
		return () -> new Document("refKey", source.id);    (1)
	}
}
// entity
{
  "_id" : "8cfb002",
  "ref" : {
    "refKey" : "9a48e32"                                   (1)
  }
}

// referenced object
{
  "_id" : "9a48e32"
}
1 用于获取参考值的密钥必须是写入时使用的密钥。
2 refKey是 的缩写。target.refKey
例 4.具有多个值构成查找查询的文档引用
class Entity {
  @DocumentReference(lookup = "{ 'firstname' : '?#{fn}', 'lastname' : '?#{ln}' }") (1) (2)
  ReferencedObject ref;
}
// entity
{
  "_id" : "8cfb002",
  "ref" : {
    "fn" : "Josh",           (1)
    "ln" : "Long"            (1)
  }
}

// referenced object
{
  "_id" : "9a48e32",
  "firstname" : "Josh",      (2)
  "lastname" : "Long",       (2)
}
1 根据查找查询从/到链接文档读取/写入键。fnln
2 使用非 id 字段查找目标文档。
例 5.从目标集合读取文档参考
class Entity {
  @DocumentReference(lookup = "{ '_id' : '?#{id}' }", collection = "?#{collection}") (2)
  private ReferencedObject ref;
}
@WritingConverter
class ToDocumentPointerConverter implements Converter<ReferencedObject, DocumentPointer<Document>> {
	public DocumentPointer<Document> convert(ReferencedObject source) {
		return () -> new Document("id", source.id)                                   (1)
                           .append("collection", … );                                (2)
	}
}
// entity
{
  "_id" : "8cfb002",
  "ref" : {
    "id" : "9a48e32",                                                                (1)
    "collection" : "…"                                                               (2)
  }
}
1 从参考文档读取/写入引用文档的键,以便在查找查询中使用它们。_id
2 可以使用其密钥从参考文档中读取集合名称。

我们知道在查找查询中使用各种MongoDB查询运算符是很诱人的,这很好。 但有几个方面需要考虑:Spring中文文档

  • 确保有支持查找的索引。Spring中文文档

  • 请注意,分辨率需要服务器 rountrip 导致延迟,请考虑懒惰策略。Spring中文文档

  • 使用运算符批量加载文档引用的集合。
    在尽最大努力的基础上,在内存中恢复原始元素顺序。 只有在使用相等表达式时才能恢复顺序,而在使用 MongoDB 查询运算符时无法恢复顺序。 在这种情况下,我们将在从商店或通过提供的属性收到结果时进行排序。
    $or@DocumentReference(sort)Spring中文文档

一些更一般的评论:Spring中文文档

  • 你使用循环引用吗? 问问你自己是否需要它们。Spring中文文档

  • 延迟文档引用很难调试。 确保工具不会意外触发代理解析,例如调用 .toString()Spring中文文档

  • 不支持使用反应式基础结构读取文档引用。Spring中文文档

1 标记要引用的值的集合。Account
2 映射框架不处理级联保存,因此请确保单独保留引用的实体。
3 添加对现有实体的引用。
4 引用的实体表示为其值的数组。Account_id
表 1.@DocumentReference默认值
属性 描述 违约

dbSpring中文文档

集合查找的目标数据库名称。Spring中文文档

MongoDatabaseFactory.getMongoDatabase()Spring中文文档

collectionSpring中文文档

目标集合名称。Spring中文文档

带批注的属性的域类型,分别是值类型(如果是 like 或属性)、集合名称。CollectionMapSpring中文文档

lookupSpring中文文档

单个文档查找查询通过 SpEL 表达式评估占位符,用作给定源值的标记。 like 或 properties 通过运算符组合单个查找。#targetCollectionMap$orSpring中文文档

使用加载的源值的基于字段的查询 ()。_id{ '_id' : ?#{#target} }Spring中文文档

sortSpring中文文档

用于在服务器端对结果文档进行排序。Spring中文文档

默认情况下无。 类似属性的结果顺序会根据已使用的查找查询在尽力而为的基础上恢复。CollectionSpring中文文档

lazySpring中文文档

如果设置为值,则在首次访问属性时会延迟解析。trueSpring中文文档

默认情况下急切地解析属性。Spring中文文档

延迟加载可能需要类代理,而类代理又可能需要访问未打开的 jdk 内部,从 Java 16+ 开始,这是由于 JEP 396:默认情况下强封装 JDK 内部。 对于这些情况,请考虑回退到接口类型(例如,从切换到 )或提供所需的参数。ArrayListList--add-opens
1 使用该字段查询集合中的实体。acronymPublisher
2 延迟加载回对集合的引用。Book
1 使用该字段查询集合中的实体。acronymPublisher
2 查找查询的字段值占位符(如 )用于形成参考文档。acc
1 通过在文档中存储 来设置从(引用)到(所有者)的链接。BookPublisherPublisher.idBook
2 将保存引用的属性标记为只读。 这样可以防止在文档中存储对单个 s 的引用。BookPublisher
3 使用变量访问文档中的值,并在此检索中使用匹配 。#selfPublisherBookspublisherId
1 MongoDB简单类型可以直接使用,无需进一步配置。
1 target 定义引用值本身。
1 用于获取参考值的密钥必须是写入时使用的密钥。
2 refKey是 的缩写。target.refKey
1 根据查找查询从/到链接文档读取/写入键。fnln
2 使用非 id 字段查找目标文档。
1 从参考文档读取/写入引用文档的键,以便在查找查询中使用它们。_id
2 可以使用其密钥从参考文档中读取集合名称。

我们知道在查找查询中使用各种MongoDB查询运算符是很诱人的,这很好。 但有几个方面需要考虑:Spring中文文档

  • 确保有支持查找的索引。Spring中文文档

  • 请注意,分辨率需要服务器 rountrip 导致延迟,请考虑懒惰策略。Spring中文文档

  • 使用运算符批量加载文档引用的集合。
    在尽最大努力的基础上,在内存中恢复原始元素顺序。 只有在使用相等表达式时才能恢复顺序,而在使用 MongoDB 查询运算符时无法恢复顺序。 在这种情况下,我们将在从商店或通过提供的属性收到结果时进行排序。
    $or@DocumentReference(sort)Spring中文文档

一些更一般的评论:Spring中文文档

  • 你使用循环引用吗? 问问你自己是否需要它们。Spring中文文档

  • 延迟文档引用很难调试。 确保工具不会意外触发代理解析,例如调用 .toString()Spring中文文档

  • 不支持使用反应式基础结构读取文档引用。Spring中文文档