Spring MongoDB manual reference

huangapple go评论60阅读模式
英文:

Spring MongoDB manual reference

问题

我正在尝试在Spring MongoDB中创建手动引用(Manual References),仅在引用字段中存储一个ObjectId,并在需要时进行填充(即不使用DBRef)。

然而,我没有找到关于如何正确实现这一点的文档。

假设我有一个简单的模型如下:

@Document(collection = "person")
public class Person {

    @Id
    private String id;

    ... 其他属性

    // 这是对Address模型的引用
    private ObjectId address;
}

以及

@Document(collection = "address")
public class Address {

    @Id
    private String id;

    ... 其他属性
}

在这里,我如何创建一个手动引用,仅在Person中存储address模型的ID,并且只在需要时填充?

更新:
为了澄清,我们的数据库中已经有很多文档,之前是使用Mongoose插入的,其中模型A包含一个引用模型B的ObjectId。使用Mongoose,我们能够在需要时调用.populate。然后当我们保存文档时,Mongoose只保存了ObjectId。

基本上,我正在尝试在Spring中实现类似的系统。
我创建了一个自定义转换器,在加载数据时将ObjectId转换为特定类型,但这个解决方案并没有帮助,因为它不能在保存时将模型转换为ObjectId。

这是我们需要的:

  1. 引用字段仅包含ObjectID或ID数组。
  2. 我们只能在需要时填充字段。
  3. 我们可以修改填充字段并调用保存方法,该方法会更新两个文档并仅保存引用字段中的ObjectId。
  4. 引用字段可以为空。
  5. 当添加新引用时,我们可以使用ObjectID或对象。在任何情况下,只应使用ObjectID。

再次强调,这正是Javascript中Mongoose的工作方式,这也是我们目前在使用的方式。

我要么需要详细的答案,要么需要某种教程,以解释如何实现这一点,因为我一直没有找到使用手动引用的示例,这非常奇怪,因为手动引用是更受欢迎和推荐的方法。

英文:

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:

  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.

答案1

得分: 1

使用 @DbRef 并且具有相同字段名称,只是将 ObjectId 列表作为模型上的另一个字段引用。

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

或者您可以在更新或插入时使用带有条件的 MongoTemplate。

final Update update = new Update();
update.push("field", modelB.getId());
mongoTemplate.updateFirst(query, update, ModelA.class);
英文:

Using @DbRef and with same field name just referencing ObjectId list as another field on the model.

public class ModelModelListener extends AbstractMongoEventListener&lt;Model&gt; {
    @Override
    public void onBeforeSave(BeforeSaveEvent&lt;Model&gt; event) {
        final Model source = event.getSource();
        final Document document = event.getDocument();
        final List&lt;Model&gt; modelList = source.getModelList();
        final List&lt;ObjectId&gt; modelIdList = source.getModelIdList();
        if (document != null)
            document.put(&quot;modelList&quot;, modelList != null ? toIdList(modelList) : modelIdList);
    }

    @Override
    public void onAfterConvert(AfterConvertEvent&lt;Model&gt; event) {
        final Model source = event.getSource();
        final Document document = event.getDocument();
        if (document != null)
            source.setModelIdList(document.getList(&quot;modelList&quot;, ObjectId.class));
    }
}

@Data // Lombok getter setter
@Document
public class Model {

    @Field(&quot;modelList&quot;)
    @DBRef(lazy = true)
    private List&lt;Model&gt; modelList;

    @Field
    private List&lt;ObjectId&gt; modelIdList;
}

Or you can use MongoTemplate with criteria when updating or inserting.

final Update update = new Update();
update.push(&quot;field&quot;, modelB.getId());
mongoTemplate.updateFirst(query, update, ModelA.class);

答案2

得分: 0

你可以修改find方法。

db.person.find({...parameters...}).forEach(function(persons) {
  persons.forEach(p => {
     db.address.find({person: p.id}).forEach(function(address) {
     person.address = address.id;
  });
});

这样做,您始终传递关系ID。
我相信没有DBRef是不可能的。

英文:

You can modify find method.

db.person.find({...parameters...}).forEach(function(persons) {
  persons.forEach(p =&gt; {
     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.

huangapple
  • 本文由 发表于 2020年10月2日 05:47:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/64163644.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定