#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 при сохранении.
Вот что нам нужно:
- Поле ссылки содержит только идентификатор объекта или массив идентификаторов.
- Мы можем заполнить поле только при необходимости.
- Мы можем изменить заполненное поле и вызвать метод сохранения, который обновляет оба документа и сохраняет только идентификатор объекта в поле ссылки.
- Поле ссылки может быть пустым для некоторых документов.
- При добавлении новой ссылки мы можем использовать либо идентификатор объекта, либо объект. В любом случае следует использовать только 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. Я отредактирую свое решение с помощью паллиативного решения. Из того, что я исследовал, нет способа сделать это путем сопоставления.