Reputation: 320
I'm trying to create manual references in Spring MongoDB to simply store an ObjectId in reference field and populate it only if needed. (i.e. Without DBRef)
However, I have not been able to find documentation on how to properly implement this.
Suppose I have a simple model like this:
@Document(collection = "person")
public class Person{
@Id
private String id;
... other attributes
//This is a reference to Address model
private ObjectId address;
}
And
@Document(collection = "address")
public class Address{
@Id
private String id;
... other attributes
}
How can I create a manual reference here to only store the address model's ID in Person and then only populate when needed?
Update:
To clarify, we already have a lot of documents on database that were previously inserted using Mongoose, where model A contains an ObjectId that references the model B. Using mongoose we were able to call .populate
on these when needed. Then when we saved the document, Mongoose only saved the ObjectId.
Basically I'm trying to implement a similar system in Spring. I created a custom converter that converts the ObjectId to the specific type when loading the data but this solution does not help since it does not convert the Model to ObjectId on save.
Here is what we need:
Again, this is exactly how Mongoose in Javascript works, which is what we are currently using.
I'm looking either for a detailed answer or a some sort of tutorial that explains how this can be implemented since I have not been able to find any examples using manual reference which is very strange since manual reference is the more popular and recommended way of doing this.
Upvotes: 4
Views: 2595
Reputation: 915
Using @DbRef and with same field name just referencing ObjectId list as another field on the model.
public class ModelModelListener extends AbstractMongoEventListener<Model> {
@Override
public void onBeforeSave(BeforeSaveEvent<Model> event) {
final Model source = event.getSource();
final Document document = event.getDocument();
final List<Model> modelList = source.getModelList();
final List<ObjectId> modelIdList = source.getModelIdList();
if (document != null)
document.put("modelList", modelList != null ? toIdList(modelList) : modelIdList);
}
@Override
public void onAfterConvert(AfterConvertEvent<Model> event) {
final Model source = event.getSource();
final Document document = event.getDocument();
if (document != null)
source.setModelIdList(document.getList("modelList", ObjectId.class));
}
}
@Data // Lombok getter setter
@Document
public class Model {
@Field("modelList")
@DBRef(lazy = true)
private List<Model> modelList;
@Field
private List<ObjectId> modelIdList;
}
Or you can use MongoTemplate with criteria when updating or inserting.
final Update update = new Update();
update.push("field", modelB.getId());
mongoTemplate.updateFirst(query, update, ModelA.class);
Upvotes: 1
Reputation: 841
You can modify find method.
db.person.find({...parameters...}).forEach(function(persons) {
persons.forEach(p => {
db.address.find({person: p.id}).forEach(function(address) {
person.address = address.id;
});
});
In doing so, you always pass the relationship ID.
I believe that there is no way without DBRef
.
Upvotes: 0