Ссылка на Spring MongoDB вручную

#java #spring #spring-boot #spring-data-mongodb

#java #spring #spring-boot #spring-data-mongodb

Вопрос:

Я пытаюсь создать ссылки вручную в Spring MongoDB, чтобы просто сохранить идентификатор объекта в поле ссылки и заполнить его только при необходимости. (т. Е. Без DBRef)

Однако я не смог найти документацию о том, как правильно это реализовать.

Предположим, у меня есть простая модель, подобная этой:

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

    @Id
    private String id;

    ... other attributes

    //This is a reference to Address model
    private ObjectId address;

}
  

И

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

    @Id
    private String id;

    ... other attributes

}
  

Как я могу создать здесь ручную ссылку, чтобы хранить идентификатор модели адреса только лично, а затем заполнять только при необходимости?

Обновление: чтобы уточнить, у нас уже есть много документов по базе данных, которые ранее были вставлены с помощью Mongoose, где модель A содержит ObjectId, который ссылается на модель B. Используя mongoose, мы смогли вызывать .populate их при необходимости. Затем, когда мы сохранили документ, Mongoose сохранил только идентификатор объекта.

По сути, я пытаюсь реализовать аналогичную систему в Spring. Я создал пользовательский конвертер, который преобразует ObjectId в определенный тип при загрузке данных, но это решение не помогает, поскольку оно не преобразует модель в ObjectId при сохранении.

Вот что нам нужно:

  1. Поле ссылки содержит только идентификатор объекта или массив идентификаторов.
  2. Мы можем заполнить поле только при необходимости.
  3. Мы можем изменить заполненное поле и вызвать метод сохранения, который обновляет оба документа и сохраняет только идентификатор объекта в поле ссылки.
  4. Поле ссылки может быть пустым для некоторых документов.
  5. При добавлении новой ссылки мы можем использовать либо идентификатор объекта, либо объект. В любом случае следует использовать только ObjectId .

Опять же, именно так работает Mongoose в Javascript, который мы сейчас используем.

Я ищу либо подробный ответ, либо какое-то руководство, в котором объясняется, как это можно реализовать, поскольку я не смог найти никаких примеров с использованием ручной ссылки, что очень странно, поскольку ручная ссылка является более популярным и рекомендуемым способом сделать это.

Ответ №1:

Используя @DBRef и с тем же именем поля, просто ссылаясь на список идентификаторов объекта в качестве другого поля в модели.

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

Комментарии:

1. Не будет ли это вставлять как modelList, так и modelIdList в db? Мне нужен только список моделей в БД.

2. @Aiden Я обновил пример, чтобы получить доступ к документу о соответствующих действиях. Посмотрите, что modelIdList — это просто представление того же поля в документе DB.

Ответ №2:

Вы можете изменить метод поиска.

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

При этом вы всегда передаете идентификатор отношения.
Я считаю, что без этого никак DBRef .

Комментарии:

1. Это имеет смысл; однако документы, которые у нас уже есть в базе данных, были ранее вставлены с помощью Mongoose, где модель A содержит ObjectId, который ссылается на модель B. Используя mongoose, мы смогли вызвать .populate для них, когда это необходимо. По сути, я пытаюсь найти способ добиться аналогичного результата с помощью Spring MongoDB

2. Итак … почему бы не использовать DBRef? Если у вас есть сопоставленные атрибуты, вы должны сопоставить их как объект.

3. Я отредактирую свое решение с помощью паллиативного решения. Из того, что я исследовал, нет способа сделать это путем сопоставления.