как обновить поля документа MongoDB, когда измененные поля не всегда одинаковы?

Скажем, у меня есть класс Foo и jax-rs FooResource, который предоставляет API для CRUD Foos.

Foo представляет собой документ MongoDB.

В FooResource у меня будет что-то вроде этого:

@PATCH
@Path("{id}")
public Response update(@PathParam("id") ObjectId id, Foo foo) {
    return Response.ok(fooService.update(id, foo)).build();
}

Проблема в том, что объект foo в json будет содержать только те поля, которые изменились, но я никогда не знаю заранее, какие это будут поля.

Я использую Quarkus с расширением Panache, и единственный способ, который я вижу, - это получить объект из БД, а затем проверить каждое поле в объекте foo, который я получил из HTTP-запроса, чтобы узнать, имеет ли он значение null или нет, а если нет, установите новое значение в сущности и в конце вызовите для него update ().

Но это стало бы кошмаром, если бы у меня был класс с десятками полей. Это настолько распространенный вариант использования, что я не могу представить (или не хочу верить), что это единственный способ сделать это.

Если бы существовал способ отправить неполный документ в MongoDB, чтобы он позаботился об изменении только полей, присутствующих в этом документе, это было бы идеально. Но я не нашел способа сделать это. Ни с quarkus (с размахом или без него), ни с драйвером java для mongo API.

Так есть ли более простой способ сделать это? Я предпочитаю решение с quarkus MongoDB с расширением Panache, но решение без Panache или даже напрямую с API драйвера java было бы в порядке.

PS: отправка полного объекта из внешнего интерфейса и замена всего документа для меня не вариант.

Спасибо.


person Fab    schedule 16.07.2020    source источник


Ответы (1)


Вы можете использовать метод update(updateDocument, updateParams).where(query, params), он обеспечивает более гибкий метод обновления.

Из примера из руководства по документации:

// set the name of all living persons to 'Mortal'
long updated = Person.update("name", "Mortal").where("status", Status.Alive);

Для вашего варианта использования часть запроса находится в поле _id, но вам все равно необходимо динамически создавать часть обновления на основе наличия поля вашего объекта Foo.

Как вы сказали, нет способа сделать это, легко подумал клиент Java, поскольку при использовании типизированной коллекции (привязка коллекции к типу Java, а не к Document) поля нулевого значения должны отражаться в базе данных (как может MongoDB клиент знает, что значение null означает, что иногда не обновляйте поле или не обновляйте поле до нуля).

Итак, для этого варианта использования вы можете:

  • Создайте обновление Document с необходимыми полями (это то, что для вас делает update (updateDocument, updateParams) .where (query, params)).
  • Сначала получите объект, объедините его вручную (для этого вы можете легко создать помощник на основе отражения), а затем обновите его.
person loicmathieu    schedule 17.07.2020
comment
Спасибо за ответ (и спасибо за расширение :)). На самом деле я подумал об использовании для этого отражения. Я просто хотел избежать этого из-за Quarkus, но здесь он действительно поможет, потому что у меня будут классы с большим количеством полей, поэтому я пойду на это. - person Fab; 17.07.2020
comment
Отражение не будет проблемой для GraalVM, если вас это беспокоит, поскольку мы регистрируем все типы сущностей для отражения. Если вы используете DTO, вы можете добавить аннотацию @RegisterForReflection. - person loicmathieu; 17.07.2020