запрос отношений родитель-потомок в simple_salesforce python, извлечение из упорядоченных dicts

#python #pandas #salesforce #soql #simple-salesforce

#python #pandas #salesforce #soql #ordereddictionary

Вопрос:

Я пытаюсь запросить информацию из salesforce, используя simple_salesforce пакет на python.

Проблема в том, что это вложение полей, которые являются частью отношения родитель-потомок, в упорядоченный dict внутри упорядоченного dict

Я хочу .. из объекта Opportunity найти идентификатор и идентификатор учетной записи, связанный с этой записью.

Запрос SOQL может выглядеть следующим образом..

 query = "select id, account.id from opportunity where closedate = last_n_days:5"
  

в SOQL (salesforce object query language) точка обозначает отношения родитель-потомок в базе данных. Итак, я пытаюсь получить идентификатор из объекта opportunity, а затем связанный идентификатор из объекта account в этой записи.

по какой-то причине идентификатор отображается нормально, но account.id вложен в упорядоченный dict внутри упорядоченного dict:

 q = sf.query_all(query)
  

это возвращает упорядоченный словарь..

 OrderedDict([('totalSize', 455),
             ('done', True),
             ('records',
              [OrderedDict([('attributes',
                             OrderedDict([('type', 'Opportunity'),
                                          ('url',
  

Я бы вытащил records часть ordereddict , чтобы создать df

 df = pd.DataFrame(q['records'])
  

Это дает мне 3 столбца, вызывается упорядоченный dict 'attributes' Id и вызывается другой упорядоченный dict 'Account' . Я ищу способ извлечь ('BillingCountry', 'United States') фрагмент из вложенного упорядоченного dict 'Account'

 [OrderedDict([('attributes',
               OrderedDict([('type', 'Opportunity'),
                            ('url',
                             '/services/data/v34.0/sobjects/Opportunity/0061B003451RhZgiHHF')])),
              ('Id', '0061B003451RhZgiHHF'),
              ('Account',
               OrderedDict([('attributes',
                             OrderedDict([('type', 'Account'),
                                          ('url',
                                           '/services/data/v34.0/sobjects/Account/001304300MviPPF3Z')])),
                            ('BillingCountry', 'United States')]))])
  

Редактировать: уточнение того, что я ищу.

Я хочу закончить фреймом данных со столбцом для каждого из запрашиваемых полей.

Когда я помещаю 'records' фрагмент в df = pd.DataFrame(sf.query_all(query)['records']) фрейм данных, используя его, я:

 attributes  Id  Account
OrderedDict([('type', 'Opportunity'), ('url', '/services/data/v34.0/sobjects/Opportunity/0061B003451RhZgiHHF')])    0061B003451RhZgiHHF OrderedDict([('attributes', OrderedDict([('type', 'Account'), ('url', '/services/data/v34.0/sobjects/Account/0013000000MvkRQQAZ')])), ('BillingCountry', 'United States')])
OrderedDict([('type', 'Opportunity'), ('url', '/services/data/v34.0/sobjects/Opportunity/0061B00001Pa52QQAR')]) 0061B00001Pa52QQAR  OrderedDict([('attributes', OrderedDict([('type', 'Account'), ('url', '/services/data/v34.0/sobjects/Account/0011300001vQPxqAAG')])), ('BillingCountry', 'United States')])
OrderedDict([('type', 'Opportunity'), ('url', '/services/data/v34.0/sobjects/Opportunity/0061B00001TRu5mQAD')]) 0061B00001TRu5mQAD  OrderedDict([('attributes', OrderedDict([('type', 'Account'), ('url', '/services/data/v34.0/sobjects/Account/0011300001rfRTrAAE')])), ('BillingCountry', 'United States')])
  

после удаления 'attributes' столбца я хочу, чтобы результат был

 Id BillingCountry
0061B003451RhZgiHHF 'United States'
0061B00001Pa52QQAR 'United States'
0061B00001TRu5mQAD 'United States'
  

Комментарии:

1. @StephenRauch Я обновил свой вопрос, чтобы внести некоторую ясность

2. Почему вы помещаете это в Dataframe? Что это вам дает? Из какой формы взяты записи sf.query_all(query) ?

3. это фактически sql-запрос из базы данных. Но по какой-то причине query функция в пакете возвращает упорядоченный dict. Я могу превратить записи из упорядоченного dict в фрейм данных, но в этом случае один из списков, которые становятся сериями при его преобразовании, на самом деле является другим упорядоченным dict.

4. Да, но. Почему вы заходите в dataframe? Это кажется дополнительным шагом, который не дает никакого значения, только путаница.

5. в какой форме вы бы его сохранили?

Ответ №1:

Pandas — потрясающий инструмент для обработки табличных данных. Но, хотя он может содержать объекты Python, это не его преимущество. Я предлагаю вам извлечь ваши данные из запроса, прежде чем вставлять их в pandas.Dataframe :

Извлечение записей:

Извлечь нужные поля в виде списка словарей так же просто, как:

 records = [dict(id=rec['Id'], country=rec['Account']['BillingCountry'])
           for rec in data['records']]
  

Вставка записей в фрейм данных:

Со списком dicts фрейм данных так же прост, как:

 df = pd.DataFrame(records)
  

Тестовый код:

 import pandas as pd
from collections import OrderedDict

data = OrderedDict([
    ('totalSize', 455),
    ('done', True),
    ('records', [
        OrderedDict([
            ('attributes', OrderedDict([('type', 'Opportunity'), ('url', '/services/data/v34.0/sobjects/Opportunity/0061B003451RhZgiHHF')])),
            ('Id', '0061B003451RhZgiHHF'),
            ('Account', OrderedDict([('attributes', OrderedDict([('type', 'Account'), ('url', '/services/data/v34.0/sobjects/Account/0013000000MvkRQQAZ')])),
                                     ('BillingCountry', 'United States')])),
        ]),
        OrderedDict([
            ('attributes', OrderedDict([('type', 'Opportunity'), ('url', '/services/data/v34.0/sobjects/Opportunity/0061B00001Pa52QQAR')])),
            ('Id', '0061B00001Pa52QQAR'),
            ('Account', OrderedDict([('attributes', OrderedDict([('type', 'Account'), ('url', '/services/data/v34.0/sobjects/Account/0011300001vQPxqAAG')])),
                                     ('BillingCountry', 'United States')])),
        ]),
        OrderedDict([
            ('attributes', OrderedDict([('type', 'Opportunity'), ('url', '/services/data/v34.0/sobjects/Opportunity/0061B00001TRu5mQAD')])),
            ('Id', '0061B00001TRu5mQAD'),
            ('Account', OrderedDict([('attributes', OrderedDict([('type', 'Account'), ('url', '/services/data/v34.0/sobjects/Account/0011300001rfRTrAAE')])),
                                     ('BillingCountry', 'United States')])),
        ]),
    ])
])

records = [dict(id=rec['Id'], country=rec['Account']['BillingCountry'])
           for rec in data['records']]
for r in records:
    print(r)

print(pd.DataFrame(records))
  

Результаты тестирования:

 {'country': 'United States', 'id': '0061B003451RhZgiHHF'}
{'country': 'United States', 'id': '0061B00001Pa52QQAR'}
{'country': 'United States', 'id': '0061B00001TRu5mQAD'}

         country                   id
0  United States  0061B003451RhZgiHHF
1  United States   0061B00001Pa52QQAR
2  United States   0061B00001TRu5mQAD
  

Комментарии:

1. идеальный ответ. Хорошо объяснено, я многому научился, и это решило мою проблему. Большое спасибо @Stephen Rauch

Ответ №2:

Pandas может читать упорядоченные dicts.

 import pandas as pd
from simple_salesforce import Salesforce

sf = Salesforce(username='your_username',   
                password='your_password',
                security_token='your_token')

query = "select id, account.id from opportunity where closedate = last_n_days:5"
df = pd.DataFrame(sf.query_all(query)['records']).drop(columns='attributes')
  

Комментарии:

1. это возможно, но это не решает проблему, когда account.id также появляется как упорядоченный dict, а не как поле. account таблица представляет собой вложенную таблицу, связанную с таблицей возможностей. Словарь в ответе Стивена — это то, как решить эту проблему. Но спасибо!