#java #mongodb #mongodb-query #upsert #mongotemplate
Вопрос:
Я использую mongo 4.2.15
Вот запись:
{ "keys": { "country": "US", "channel": "c999" }, "counters": { "sale": 0 }, "increments": null }
Я хочу иметь возможность инициализировать набор счетчиков, а также counters.sale
значение приращения и сохранить снимок результата приращения в increments
свойстве. Что-то вроде того:
db.getCollection('counterSets').update( { "$and" : [ { "keys.country" : "US"}, { "keys.channel" : "c999"} ] }, { "$inc" : { "counters.sale" : 10 }, "$set" : { "keys" : { "country" : "US", "channel" : "c999"}, "increments": { "3000c058-b8a7-4cff-915b-4979ef9a6ed9": {"counters" : "$counters"} } } }, {upsert: true})
В результате получается:
{ "_id" : ObjectId("61965aba1501d6eb40588ba0"), "keys" : { "country" : "US", "channel" : "c999" }, "counters" : { "sale" : 10.0 }, "increments" : { "3000c058-b8a7-4cff-915b-4979ef9a6ed9" : { "counters" : "$counters" } } }
Возможно ли выполнить такое обновление, которое представляет собой некоторый результат приращения копирования от корневого объекта counters
к дочернему increments.3000c058-b8a7-4cff-915b-4979ef9a6ed9.counters
с помощью одной вставки. Я хочу реализовать безопасное внедрение. Может быть, вы можете предложить какой-нибудь другой дизайн?
Комментарии:
1. Вы пробовали явно устанавливать каждый счетчик?
"counters.sale": "$counters.sale"
2. @geobreze Результат таков
"increments" : { "3000c058-b8a7-4cff-915b-4979ef9a6ed9" : { "counters.sale" : "$counters.sale" } }
Ответ №1:
Чтобы использовать выражения, вы $set
должны быть частью конвейера агрегации. Таким образом, ваш запрос должен выглядеть следующим образом
ПРИМЕЧАНИЕ: Я добавил квадратные скобки в обновление
db.getCollection('counterSets').update( { "$and" : [ { "keys.country" : "US"}, { "keys.channel" : "c999"} ] }, [ {"$set": {"counters.sale": {"$sum":["$counters.sale", 10]}}}, {"$set": {"increments.x": "$counters"}}], {upsert: true})
Я не нашел никакой информации об атомарности конвейеров агрегации, поэтому используйте это осторожно.
Комментарии:
1. Спасибо за ответ. Это меня устраивает. Эти запросы должны выполняться в многопоточном режиме. Я создам тест для проверки атомарности и сообщу, безопасен ли он для потоков.
2. Хорошо, само решение является потокобезопасным, но производительность не так уж велика. Для пустой базы данных 1000 входов на том же счетчике, установленном со 100 потоками, заняли 118 секунд.