Я пишу приложение, которое нуждается в семантике сравнения и установки в mon go.
У меня есть небольшая коллекция A
(до 200 или около того в производстве) документов, которые выглядят например:
{
_id: str,
field: str
last_known_version: int,
data: binary_blob
}
И иметь путь к коду:
Считывает текущие данные и текущие последние известные версии (LKV) как словари field -> value
из A.
Затем выполняет некоторые вычисления для данных, находя новую последнюю известную версию.
- Затем он пытается обновить документы в коллекции A, где последняя известная версия не изменилась по сравнению с тем, что мы прочитали (по существу, оптимистично делает сравнение и набор), возвращая
field
s где обновление прошло успешно - Наконец, мы делаем дальнейшие расчеты на основе успешных обновлений полей.
В псевдокоде это выглядит примерно так:
def operation():
data_by_field, lkv_by_field = read_data_and_last_known_version_by_field(A)
new_data_by_field, new_lkv = process(data_by_field)
successful_updates: Set[str] = compare_and_set(
new_data,
expected_version=lkv_by_field,
new_version=new_lkv
)
conditionally_do_more_stuff(successful_updates)
Моя проблема в том, как вернуть значения из сравнения и установки. Я мог бы сделать find_one_and_update для каждого поля:
successful = {}
for field in fields:
r = A.find_one_and_update(
{'_id': id_from_field(field), 'last_known_version': expected_last_known_version},
{
'$setOnInsert': {
'field': field
},
'set': {
'data': data[field],
'last_known_version': lkv[field]
}
},
projection='field',
upsert=True
)
for doc in r:
sucessful.add(doc['field'])
Но я не хочу брать на себя 200 сетевых обращений к серверу mon go или навязывать причинный порядок того, как происходят эти обновления. Поэтому вместо этого я хотел бы иметь возможность использовать bulk_write
с набором предварительно рассчитанных аппетов.
upserts = []
for field in fields:
upserts.append(
UpdateOne(
filter={'_id': id_from_field(field), 'last_known_version': expected_last_known_version},
update={
'$setOnInsert': {
'field': field
},
'set': {
'data': data[field],
'last_known_version': lkv[field]
}
},
upsert=True
)
)
A.bulk_write(upserts, ordered=False)
Однако, насколько мне известно, не существует очевидного способа вернуть документ из UpdateOne или массового написания. Кроме того, не составит труда вычислить field
s из _id
любых обновленных или вставленных документов, поэтому было бы полезно вернуть _id
.
Есть ли идиоматизм c способ сделать это в пн go?