Upsert-Обновление нескольких полей документа, включая списки и вложенные списки, используя pyMongo - PullRequest
0 голосов
/ 26 августа 2018

У меня есть коллекция с такими документами:

{
"_id"    : "1234567890",
"area"   : "Zone 63",
"last_state" : "Cloudy",
"recent_indices" : [
        21,
        18,
        33,
        ...
        38
        41
  ],

"Report_stats" : [
 {
        "date_hour" : "2017-01-01 01",
        "count"     : 31
     },
 {
        "date_hour" : "2017-01-01 02",
        "count"     : 20
     },
        ...
     {
        "date_hour" : "2018-08-26 13",
        "count"     : 3
     }     
  ]
}

, которая должна обновляться на основе некоторых онлайн-отчетов в реальном времени, и предполагается, что каждый отчет выглядит следующим образом:

{
 'datetime' : '2018-08-26 13:48:11.677635',
 'areas'    : 'Zone 3; Zone 45; Zone 63',
 'status'   : 'Clear',
 'index'    : '33'
 }

Теперь мне нужно обновить коллекцию таким образом, чтобы:

  1. Каждый раз, когда в отчете появляется новая «область» (скажем, «Зона 1025»), добавляется новый документ для сохранения связанных данных.
  2. Новый «индекс» добавляет в список «Recent_indices», в то время как «last_state» обновляется до «status»
  3. , в зависимости от значения «datetime», соответствующий «Report_stats.count» увеличивается на 1или новый документ «Report_stats» («datetime» с часовым разрешением, где его «count» равно 1).

Способ выполнения каждого из этих обновлений отдельно, как-то очевиден,проблема: как я могу сделать все это одновременно в одной задаче обновления / вставки?

Я пытался использовать update_one и find_one_and_update (а также update и find_and_modify), используя pyMongo,но не было возможности (по крайней мере для меня) решить проблемуlem.

Так что я начал задаваться вопросом, возможно ли выполнить простую / единственную задачу, или мне следует начать пытаться исправить ее совсем по-другому.

Можете ли вы помочьмне как это сделать или (так как много данных собирается и, следовательно, должно обрабатываться) предложить недорогую альтернативу?

Спасибо!

Ответы [ 3 ]

0 голосов
/ 27 августа 2018

Лучшее решение, которое я достиг на данный момент, это:

if mycollection.find_one({'area': 'zone 45', 'Report_stats.date_hour': '2018-08-26 13'}):
    mycollection.update_one({'area': 'zone 45', 'Report_stats.date_hour': '2018-08-26 13'},
                                    {
                                    '$inc': {
                                        'Report_stats.$.count': 1
                                        },
                                    '$set': {
                                        'last_state': 'Clear'
                                        },
                                    '$push': {
                                        'recent_indices': 33,
                                        }
                                    },
                     )
else:
    mycollection.update_one({'area': 'zone 45'},
                                     {
                                     '$set': {
                                         'last_state': 'Clear'
                                         },
                                     '$push': {
                                         'recent_indices': 33,
                                         'Report_stats':{'date_hour':'2018-08-26 13', 'count':1}
                                         }
                                     },
                                     upsert = True
                     )

Однако он все еще выполняет один запрос дважды, чтобы обновить один документ на основе одного запроса, что не совсем удовлетворительно.

Есть лучшие предложения?

0 голосов
/ 27 августа 2018

Что, если я понял из вашего ответа, что если Report_stats.date_hour exists in your document, then you increment the counter or else you just push a new document.

Я считаю, что мы можем сделать это, используя $ cond или $ switch . Можете ли вы взглянуть.

https://docs.mongodb.com/manual/reference/operator/aggregation/cond/#exp._S_cond

Тем временем я пытаюсь написать для вас весь запрос и посмотрим, работает ли он.

Спасибо, Каника

0 голосов
/ 26 августа 2018

Я не уверен, что понимаю ваш вопрос, но если ваша проблема связана с upsert, то есть обновите его или добавьте запись, если ее там нет.Вы можете сделать это, добавив один параметр, подобный этому:

update_one( {'_id':1}, {$set:{}}, upsert=True )

Если вы хотите обновить несколько полей, вы можете просто сделать это, установив обновленный документ:

{
    name: 'Kanika',
    age: 19
},
//set document
{
    name: 'Andy',
    age: 30
}

Пожалуйста, попробуйте поискатьв: https://docs.mongodb.com/manual/reference/method/db.collection.update/, если это поможет.

Спасибо, Каника

...