简体   繁体   中英

Spring MongoDB manual reference

I'm trying to create manual references in Spring MongoDB to simply store an ObjectId in reference field and populate it only if needed. (ie 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:

  1. Reference field contains only an ObjectID or an array of IDs.
  2. We can populate the field only when needed.
  3. We can modify the populated field and call the save method, which updates both documents and only saves the ObjectId in the reference field.
  4. Reference field can be empty for some documents.
  5. When adding a new reference we can use either the ObjectID or the object. In either case, only ObjectID should be used.

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.

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);

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 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM