Можно ли вызывать функции в операторах обновления pymon go? - PullRequest
1 голос
/ 01 мая 2020

Я попытался добавить другое поле к документам в MongoDB, используя pyMon go. В качестве примера я получил случайных пользователей из здесь , и я собираюсь добавить еще одно поле в «зарегистрированную» часть:

from datetime import datetime
from pymongo import MongoClient 

client = MongoClient('localhost', 27017)
db = client['metadata']
db.users.update_many({},
[{
    "$set":{
        "registered.newField" : "$registered.date"        
    }
}])

Это работает отлично, но всякий раз, когда я иду чтобы использовать другую функцию и использовать "$registered.date" в качестве входного параметра, кажется, "registered.date" больше не анализируется.

db.users.update_many({},
[{
    "$set":{    
        "registered.newField" : 
            datetime.strptime(
              "$registered.date" ,
              "%Y-%m-%dT%H:%M:%S.%fZ").year 
    }
}])

это исключение выброса:

time data '$ register.date 'не соответствует формату'% Y-% m-% dT% H:% M:% S.% fZ '

так выглядят документы:

 {
      "gender": "male",
      "name": {
        "title": "mr",
        "first": "brad",
        "last": "gibson"
      },    
      "registered": {
        "date": "2002-05-21T10:59:49.966Z",
        "age": 17
      },
      .....
}

Ответы [ 2 ]

1 голос
/ 01 мая 2020

Вы не можете использовать функцию языка программирования для значения существующего поля в конвейере агрегации. Так что это значит ? - Когда вы напишите что-то вроде:

db.users.update_many({},
[{
    "$set":{    
        "registered.newField" : 
            datetime.strptime(
              "$registered.date" ,
              "%Y-%m-%dT%H:%M:%S.%fZ").year 
    }
}])

, тогда функция в строке ниже:

datetime.strptime( "$registered.date" , "%Y-%m-%dT%H:%M:%S.%fZ").year 

будет выполнена на сервере приложений и выдаст результат до обращения к базе данных, так что результат будет обновлен до поля "registered.newField". Поскольку эта операция выполняется перед нажатием на БД, ваш запрос не сможет получить значение "$registered.date". Таким образом, выполнение datetime.strptime().year в python фактически рассматривает "$registered.date" как строку, а не получает значение поля и затем преобразует его. Поскольку строка "$registered.date" не имеет формата "% Y-% m-% dT% H:% M:% S.% fZ", эта функция не будет выполнена.

Для проверки - я бы сказал, что вы можете попытайтесь передать жестко запрограммированное значение, чтобы оно функционировало как datetime.strptime( "2002-05-21T10:59:49.966Z" , "%Y-%m-%dT%H:%M:%S.%fZ").year, тогда .update() наверняка сработает.

Разрешение:

Поскольку вы используете это datetime.strptime().year только для получения года, тогда вы фактически используете операторы агрегирования $ year :

db.users.update_many({}, [
  {
    $set: {
      "registered.newField": { $year: "$registered.date" }
    }
  }
]);

Тест: mongoplayground

Я предполагаю, что ваше поле "$registered.date" имеет тип Date что-то вроде ISODate('2002-05-21T10:59:49.966Z'), Если в любом случае, если это тип строки, используйте $ dateFromString для преобразования в Date и затем получить год:

db.users.update_many({}, [
  {
    $set: {
      "registered.newField": {
        $year: {
          $dateFromString: {
            dateString: "$registered.date"
          }
        }
      }
    }
  }
]);

Тест: mongoplayground

1 голос
/ 01 мая 2020

Да, вы можете вызывать функции вызова в обновлении Pymon go; то, что вы не можете сделать, это изменить правила в вашем примере и положиться на оператор $, чтобы передать значение предыдущего этапа в функцию.

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

from pymongo import MongoClient
import datetime
import pprint

db = MongoClient("mongodb://localhost:27019/")['mydatabase']

db.users.insert_one( {
      "gender": "male",
      "name": {
        "title": "mr",
        "first": "brad",
        "last": "gibson"
      },
      "registered": {
        "date": "2002-05-21T10:59:49.966Z",
        "age": 17
      }
})

for record in db.users.find():
    try:
        date_str = record['registered']['date']
    except KeyError:
        continue
    year = datetime.datetime.strptime(date_str, "%Y-%m-%dT%H:%M:%S.%fZ").year
    db.users.update_one({'_id': record['_id']}, {'$set': {'registered.newField': year}})

pprint.pprint(db.users.find_one())
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...