Skip to content

Add support for flexible document references #3602

Closed
@christophstrobl

Description

@christophstrobl

The goal is support linking documents without the need of using the fixed structure of a DBRef (related to: #2780).

Linking via Entity id

The @Id value of the referenced entity is used for linking.
The domain type serves as collection source on read.

class Order {
	
	@Id Long orderId;

	@ManualReference
	Customer customer;
}

class Customer {
	@Id Long customerId;
}
// write
{
	'_id' : 1,
	'customer' : 100,
}

// read
db.customer.find({ '_id' : 100 }).limit(1)

Linking via custom object

The reference value used for storing is provided via a DomainType -> ObjectReference converter.
The lookup attribute uses SpEL to create the filter query following the annotated query syntax from @Query. The target collection that can be either read from the source document, domain type or is a fixed value.

class CustomerReferenceConverter implements Converter<Customer, ObjectReference> {

	public ObjectReference convert(Customer source) {
		return new org.bson.Document("id", source.getId())
			.append("collection", "customers");
	}
}

class Order {
	
	@Id Long orderId;

	@ManualReference(lookup = "{ '_id' : '?#{id}' }", collection = "?#{collection}")
	Customer customer;
}
// write
{
	'_id' : 1,
	'customer' : {
		'id' : 100,
		'collection' : 'customers'
	}
}

// read
db.customers.find({ '_id' : 100 }).limit(1)

The lookup filter can contain any valid expression as long as it is resolvable against the stored reference.

Linking multiple entities

Linking a collection of entities follows the same conversion patterns as described above. The main difference is that the values are stored within an array.
The provided filter expression is created for every entry and concatenated via the $or operator.

class Customer {
	
	@Id Long customerId;

	@ManualReference(lookup = "{ '_id' : '?#{target}' }")
	List<Order> orders;
}
// write
{
	'_id' : 100,
	'orders' : [1,2,3,5,8]
}

// read
db.order.find({ '$or' : [ { '_id' : 1 }, { '_id' : 2 }, ...] })

Element order can be messed up when loading documents from the store this way. The original order must be restored by using the filter as a reference without having to fetch objects one by one.

Lazy Loading

References can be resolved lazily delaying resolution on first access.
In this case on read a proxy is generated holding the actual source value and the lookup filter.

class Order {
	
	@Id Long orderId;

	@ManualReference(lazy = true)
	Customer customer;
}

Object methods like (toString) on unresolved proxies shall not trigger resolution but be served from the available source value. On write, in case the Proxy never got resolved, the original source is written back to the collection without an attempt of resolving it.

Metadata

Metadata

Labels

Type

No type

Projects

No projects

Relationships

None yet

Development

No branches or pull requests

Issue actions