Внедрение MongoDB i18n с данными Spring - PullRequest
0 голосов
/ 31 марта 2020

Я ищу элегантное решение для сохранения локализованных данных в MongoDB в моем приложении Spring.

В приведенном ниже примере есть базовое c решение для сохранения локализованных данных для поля description .

Как уже предлагалось в how-to-do-i18n-with-mongodb схема для локализованных данных:

"description": [{ "locale": "es", "value": "someESvalue" }, { "locale": "en", "value": "someENvalue" }]

Учитывая что сущность выглядит так:

@Document(collection = "foo")
public class Foo implements Serializable {

    @Id
    private String id;

    @Field("description")
    private List<LocalizedValue> description;

    // Getters and Setters are omitted in all classes

LocalizedValue содержит и локаль, и значение

public class LocalizedValue {

    private Locale locale;
    private String value;

И DTO выглядит так:

public class FooDTO {

    private String id;
    private String description;

В служба save и обновление (или customUpdate) обрабатываются по-разному

@Service
public class FooServiceImpl implements FooService {

public FooDTO save(FooDTO dto) {
    // String is converted to List<LocalizedValue> in this step 
    Foo foo = entityMapper.toEntity(dto);
    if (StringUtils.isBlank(foo.getId())) {
        // save and update must be treated differently
        foo = fooRepository.save(foo);
    } else {
        foo = fooRepository.customUpdate(foo);
    }

Обратите внимание, что преобразователь обрабатывает преобразование из поля String description в DTO в List<LocalizedValue> description в entity.

На этом этапе обновление или вставка LocalizedValue в массив description становится проблемой. Для этого есть собственный метод репозитория.

public class FooRepositoryImpl implements FooRepositoryCustom {

    private final MongoTemplate mongoTemplate;

    public FooRepositoryImpl(MongoTemplate mongoTemplate) {
        this.mongoTemplate = mongoTemplate;
    }

    public Foo customUpdate(Foo foo) {

        Query query = new Query();
        query.addCriteria(Criteria.where("id").is(foo.getId()).andOperator(
Criteria.where("description.locale").is(foo.getDescription().get(0).getLocale().toString())));

        List<Foo> foos = mongoTemplate.find(query, Foo.class);

        Update update = new Update();
        UpdateResult writeResult;

        // insert a new LocalizedValue or update an existing one
        if (CollectionUtils.isEmpty(foos)) {
            query = new Query();
            query.addCriteria(Criteria.where("id").is(foo.getId()));
            update.addToSet("description", foo.getDescription().get(0));
            writeResult = mongoTemplate.upsert(query, update, Foo.class);
        } else {
            update.set("description.$.value", foo.getDescription().get(0).getValue());
            writeResult = mongoTemplate.updateFirst(query, update, Foo.class);
        }

        // Here you may need to update manually any other fields Foo may have ! 

Этот пример работает, но, на мой взгляд, это довольно уродливое решение. Вам по-прежнему необходимо создать собственный репозиторий для каждой из ваших сущностей и написать (и выполнить) несколько запросов. Даже если вам удастся дополнительно оптимизировать запросы (возможно, с помощью Aggregation Framework), для каждого поля каждой сущности, которую вы можете захотеть локализовать, необходимо выполнить множество ненужных шагов.

Основная проблема заключается в управление этим массивом:

"description": [{ "locale": "es", "value": "someESvalue" }, { "locale": "en", "value": "someENvalue" }]

Если locale не существует, вы должны вставить новый элемент, если locale существует, вы должны обновить его value.

Я думаю о расширении MongoRepository и рассмотрении этих операций в общем виде c.

Что вы думаете о i18n с MongoDB? Знаете ли вы лучшее решение?

Заранее спасибо.

...