Регистрация  |  Вход

DATALOADER + PYTHON

Нужно было выгрузить с одного орга на другой большое количество связанных записей COUNTRY -> CITY -> AIRPORT

COUNTRY выгрузились очень легко и просто потому что это parent
CITY - пришлось помучаться и подумать(10тысяч записей руками не обновишь), потому как нужно было обновлять COUNTRY__c в соотвтствие с данными орга

Если кому нужно, то вот решение;


    Выгружаем COUNTRY и мапим ID из CSV в ExternalId__c поле
    Делаем ЭКСПОРТ и экспортируем Id, ExternalId__c
    ставим python и либу pandas

import pandas as pd
sep = ","
path_file_1 = "/users/maxim_elets/desktop/csv/cities.csv"
data1 = pd.read_csv(path_file_1, sep=sep, error_bad_lines=False)
path_file_2 = "/users/maxim_elets/desktop/countries_export.csv"
data2 = pd.read_csv(path_file_2, sep=sep, error_bad_lines=False)
data2_dict = dict(zip(data2.EXTERNALID__C, data2.ID))
data1["COUNTRY__C"].replace(data2_dict,inplace=True)
data1.to_csv("/users/maxim_elets/desktop/csv/replaced_cities.csv", mode = 'w', index=False)

Ну и дальше загружаем все это через даталоадер.

Если есть варианты проще, прошу отписаться :)

Нужно было выгрузить с одного орга на другой большое количество связанных записей COUNTRY -> CITY -> AIRPORT

COUNTRY выгрузились очень легко и просто потому что это parent
CITY - пришлось помучаться и подумать(10тысяч записей руками не обновишь), потому как нужно было обновлять COUNTRY__c в соотвтствие с данными орга

Если кому нужно, то вот решение;

[list]
Выгружаем COUNTRY и мапим ID из CSV в ExternalId__c поле
Делаем ЭКСПОРТ и экспортируем Id, ExternalId__c
ставим python и либу pandas
[/list]
[code]
import pandas as pd
sep = ","
path_file_1 = "/users/maxim_elets/desktop/csv/cities.csv"
data1 = pd.read_csv(path_file_1, sep=sep, error_bad_lines=False)
path_file_2 = "/users/maxim_elets/desktop/countries_export.csv"
data2 = pd.read_csv(path_file_2, sep=sep, error_bad_lines=False)
data2_dict = dict(zip(data2.EXTERNALID__C, data2.ID))
data1["COUNTRY__C"].replace(data2_dict,inplace=True)
data1.to_csv("/users/maxim_elets/desktop/csv/replaced_cities.csv", mode = 'w', index=False)
[/code]

Ну и дальше загружаем все это через даталоадер.

Если есть варианты проще, прошу отписаться :)

Можно сделать тоже самое, но через Excel без питона.

Можно сделать тоже самое, но через Excel без питона.

Gres
Можно сделать тоже самое, но через Excel без питона.

Расскажи плиз, как.

[quote="Gres"]Можно сделать тоже самое, но через Excel без питона.[/quote]
Расскажи плиз, как.

чисто теоретически, на практике не перименял, может гдето не так понимаю ?

1 сделать по external ID text полю на COUNTRY and CITY (только в новом орге)
2 забить оба поля данными прямо в CSV или Excel , используя старый SFDC ID t.e. рекорд COUNTRY будет иметь External text ID со значением SFDC ID в старом орге. По сути переименовать ID в ExternalId__c прямо в CSV.
3 загрузить парента вместе с новым External ID полем, загрузить чайлда используя связь по external ID (чайлда соответственно тянуть со старого орга вместе с parent ID) see link below
4 повторить для грандчайлда по той же схеме
5 удалить external ID поля с нового орга

https://help.salesforce.com/articleView?id=000320964&type=1&mode=1

чисто теоретически, на практике не перименял, может гдето не так понимаю ?

1 сделать по external ID text полю на COUNTRY and CITY (только в новом орге)
2 забить оба поля данными прямо в CSV или Excel , используя старый SFDC ID t.e. рекорд COUNTRY будет иметь External text ID со значением SFDC ID в старом орге. По сути переименовать ID в ExternalId__c прямо в CSV.
3 загрузить парента вместе с новым External ID полем, загрузить чайлда используя связь по external ID (чайлда соответственно тянуть со старого орга вместе с parent ID) see link below
4 повторить для грандчайлда по той же схеме
5 удалить external ID поля с нового орга

https://help.salesforce.com/articleView?id=000320964&type=1&mode=1

Андрей
чисто теоретически, на практике не перименял, может гдето не так понимаю ?

1 сделать по external ID text полю на COUNTRY and CITY (только в новом орге)
2 забить оба поля данными прямо в CSV или Excel , используя старый SFDC ID t.e. рекорд COUNTRY будет иметь External text ID со значением SFDC ID в старом орге. По сути переименовать ID в ExternalId__c прямо в CSV.
3 загрузить парента вместе с новым External ID полем, загрузить чайлда используя связь по external ID (чайлда соответственно тянуть со старого орга вместе с parent ID) see link below
4 повторить для грандчайлда по той же схеме
5 удалить external ID поля с нового орга

https://help.salesforce.com/articleView?id=000320964&type=1&mode=1

External Id в любом случае нужен, чтобы мапить значения правильно.

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

[quote="Андрей"]чисто теоретически, на практике не перименял, может гдето не так понимаю ?

1 сделать по external ID text полю на COUNTRY and CITY (только в новом орге)
2 забить оба поля данными прямо в CSV или Excel , используя старый SFDC ID t.e. рекорд COUNTRY будет иметь External text ID со значением SFDC ID в старом орге. По сути переименовать ID в ExternalId__c прямо в CSV.
3 загрузить парента вместе с новым External ID полем, загрузить чайлда используя связь по external ID (чайлда соответственно тянуть со старого орга вместе с parent ID) see link below
4 повторить для грандчайлда по той же схеме
5 удалить external ID поля с нового орга

https://help.salesforce.com/articleView?id=000320964&type=1&mode=1[/quote]

External Id в любом случае нужен, чтобы мапить значения правильно.

Смысл скрипта в том, что все что нужно - это указать путь к csv и указать откуда какие поля/значения мапить.
Просто я допустим хз как в Excel можно заменить значения в колонке используя мапу - старый айди: новый айди.
Вот - https://support.office.com/en-us/article/vlookup-function-0bbc8083-26fe-4963-8ab8-93a18ad188a1

DevNull
Вот - https://support.office.com/en-us/article/vlookup-function-0bbc8083-26fe-4963-8ab8-93a18ad188a1

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

У меня есть файл Города, csv - 10000 строк; В нем лежит Country__c - айди Страны
Я выгружаю себе на орг файл Страны.csv
Мне нужно заменить в файле города.csv старые Id на новые (с моего орга)

На питоне я просто указываю путь к Города.csv + Страны_export.csv
И говорю что хочу заменить Город.Country__c на то что залилось в мой орг.

А с vlookup что-то не понятно

[quote="DevNull"]Вот - https://support.office.com/en-us/article/vlookup-function-0bbc8083-26fe-4963-8ab8-93a18ad188a1[/quote]

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

У меня есть файл Города, csv - 10000 строк; В нем лежит Country__c - айди Страны
Я выгружаю себе на орг файл Страны.csv
Мне нужно заменить в файле города.csv старые Id на новые (с моего орга)

На питоне я просто указываю путь к Города.csv + Страны_export.csv
И говорю что хочу заменить Город.Country__c на то что залилось в мой орг.

А с vlookup что-то не понятно 

vlookup позволяет вытянуть данные из одного файла в другой основываясь на каком либо значении. Я tuj использую что бы смапить данные по External Id и Sf Id

vlookup позволяет вытянуть данные из одного файла в другой основываясь на каком либо значении. Я tuj использую что бы смапить данные по External Id и Sf Id

А зачем в файле City.csv обновлять Country__c новыми айдишками?


Почему бы не использовать старые id как externalId поля и по ним мапить в даталоадере?

А зачем в файле City.csv обновлять Country__c новыми айдишками?


Почему бы не использовать старые id как externalId поля и по ним мапить в даталоадере?

Dummy
А зачем в файле City.csv обновлять Country__c новыми айдишками?


Почему бы не использовать старые id как externalId поля и по ним мапить в даталоадере?

я и пытался обьяснить этот подход.. надо только переименовать header в csv и готово

[quote="Dummy"]А зачем в файле City.csv обновлять Country__c новыми айдишками?


Почему бы не использовать старые id как externalId поля и по ним мапить в даталоадере?[/quote]

я и пытался обьяснить этот подход.. надо только переименовать header в csv и готово

Андрей
Dummy
А зачем в файле City.csv обновлять Country__c новыми айдишками?


Почему бы не использовать старые id как externalId поля и по ним мапить в даталоадере?

я и пытался обьяснить этот подход.. надо только переименовать header в csv и готово

Да все верно, это так и работает, без велосипедов.

[quote="Андрей"][quote="Dummy"]А зачем в файле City.csv обновлять Country__c новыми айдишками?


Почему бы не использовать старые id как externalId поля и по ним мапить в даталоадере?[/quote]

я и пытался обьяснить этот подход.. надо только переименовать header в csv и готово[/quote]

Да все верно, это так и работает, без велосипедов.

Что-то я не нашел в Dataloader место где можно замапить айдишки по другому объекту?

Может у меня приложение кривое? Все что позволяет мне оно сделать это замапить филды из CSV в филды выбранного объекта?

Или я иду, делаю ExternalCountry__c поле, делаю маппинг с City.csv|Country__c в City__c.ExternalCountry__c?
А дальше что?


Умоляю запишите видос для меня тупого, это не займет много вашего времени, но поможет мне разобраться.

Что-то я не нашел в  Dataloader место где можно замапить айдишки по другому объекту?

Может у меня приложение кривое? Все что позволяет мне оно сделать это замапить филды из CSV в филды выбранного объекта?

Или я иду, делаю ExternalCountry__c поле, делаю маппинг с  City.csv|Country__c в City__c.ExternalCountry__c?
А дальше что?


[color=red]Умоляю запишите видос для меня тупого, это не займет много вашего времени, но поможет мне разобраться.[/color]

нужно следовать принципам из туториала https://help.salesforce.com/articleView?id=000320964&type=1&mode=1

скорее всего ты пропустил чтото из этого :

1 поле которое temporary external id должно быть помечено как unique
2 надо выбирать именно UPSERT а не IMPORT. почему то в импорте нельзя замапить по external id а в апсерте можно

я создал обьекты CITYTEST и COUNTRYTEST в сэндбоксе.
На CITYTEST есть master detail COUNTRYTEST__C.
также создал по 1 data полю, Data на City и ParentData на паренте.
создал 10 рекордов парентов и 10 чайлдов и скачал. данные выглядят так.

https://i.imgur.com/YkD9gXD.jpg

дальше в другомсэндбоксе
переименовываем прямо в хедере на COUNTRYTEST ID в X__c и создаем это самое поле на COUNTRYTEST. Поле должно быть text, unique и external ID. Загружаем данные на орг. Старый ID загружается в новое тестовое поле X__с.

https://i.imgur.com/d2XWyPJ.jpg

на чайлде CITYTEST я удалил ID из csv, как из хедера так и из данных. Тебе надо повторить процесс, создать еще один external ID etc для того чтобы сделать grandchild, я не собирался возиться с этим. ID надо удалить или переименовать потому что он автоматически маппится во время upsert и от этого нельзя избавиться.
дальше нажимаем upsert и выбираем наш CITYTEST. Data loader детектит что на паренте есть пододящий для маппинга external id и дает нам его навыбор.

https://i.imgur.com/WJIdK7w.jpg

собственно выбираем наше поле X__c как External ID. потом еще раз маппим внутри mapping dialog. Конечный результат:
https://i.imgur.com/4t2VFLp.jpg

нажимаем finish и чайлды маппятся по старому парент ID загруженному в другое поле. После того как data load процесс закончен поле X__c можно удалить.
Если ты хочешь еще загрузить грандчайлда то надо вместо удаления ID с CITY создать новое поле Y__c и загрузить в него старые ID CITY чтобы повторить потом процесс.

нужно следовать принципам из туториала https://help.salesforce.com/articleView?id=000320964&type=1&mode=1

скорее всего ты пропустил чтото из этого :

1 поле которое temporary external id должно быть помечено как unique
2 надо выбирать именно UPSERT а не IMPORT. почему то в импорте нельзя замапить по external id а в апсерте можно

я создал обьекты CITYTEST и COUNTRYTEST в сэндбоксе. 
На CITYTEST есть master detail COUNTRYTEST__C. 
также создал по 1 data полю, Data на City и ParentData на паренте. 
создал 10 рекордов парентов и 10 чайлдов и скачал. данные выглядят так.

https://i.imgur.com/YkD9gXD.jpg

дальше в другомсэндбоксе
переименовываем прямо в хедере на COUNTRYTEST ID в X__c и создаем это самое поле на COUNTRYTEST. Поле должно быть text, unique и external ID. Загружаем данные на орг. Старый ID загружается в новое тестовое поле X__с.

https://i.imgur.com/d2XWyPJ.jpg

на чайлде CITYTEST  я удалил ID из csv, как из хедера так и из данных. Тебе надо повторить процесс, создать еще один external ID etc для того чтобы сделать grandchild, я не собирался возиться с этим. ID надо удалить или переименовать потому что он автоматически маппится во время upsert и от этого нельзя избавиться.
дальше нажимаем upsert и выбираем наш CITYTEST. Data loader детектит что на паренте есть пододящий для маппинга external id и дает нам его навыбор.

https://i.imgur.com/WJIdK7w.jpg

собственно выбираем наше поле X__c как External ID. потом еще раз маппим внутри mapping dialog. Конечный результат:
https://i.imgur.com/4t2VFLp.jpg

нажимаем finish и чайлды маппятся по старому парент ID загруженному в другое поле. После того как data load процесс закончен поле X__c можно удалить.
Если ты хочешь еще загрузить грандчайлда то надо вместо удаления ID с CITY создать новое поле Y__c и загрузить в него старые ID CITY чтобы повторить потом процесс.

Андрей
нужно следовать принципам из туториала https://help.salesforce.com/articleView?id=000320964&type=1&mode=1

БЛЯ!
Вот оно че! А я то только делал insert/updated, у них все одинаковое, а до upserta не дошел, подумал что там тоже самое! А в нем оказывается можно настраивать matching!! От оно че, Михалыч!

Спасибо!

[quote="Андрей"]нужно следовать принципам из туториала https://help.salesforce.com/articleView?id=000320964&type=1&mode=1[/quote]

БЛЯ!
Вот оно че! А я то только делал insert/updated, у них все одинаковое, а до upserta не дошел, подумал что там тоже самое! А в нем оказывается можно настраивать matching!! От оно че, Михалыч!

[size=30][color=green]Спасибо![/color][/size]

Вообще если кому интересно, то можно легко автоматизировать миграцию данных на pure python (как и на любом другом ЯП) и скрипт будет не таким сложным. И не надо будет заморачиваться с дополнительными ExternalID полями. Понятно что для одноразового использования и для двух связанных объектов это перебор, но если миграцию данных надо автоматизировать и связанных объектов будет десятки то мутить скрипт самое то.

Используем следующие SF API enpdoints:
1. Достаем данные - https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/dome_query.htm
2. Загружаем данные - https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/dome_composite_sobject_tree_flat.htm

Вся магия кроется в referenceId. Переносим Id в attributes.referenceId и после загрузки на орг получаем мапу в таком виде: referenceId (он же Old Id) -> New Id (по второй ссылке можно глянуть живой пример ответа с мапой). Проходимся по child рекордам, заменяем все parent old ID на новый ID и загружаем. Повторяем процедуру для все child объектов вниз по иерархии.

Профит!

Из особенностей которые немного усложняют скрипт:
- данные достаются пачками до 2000 записей, поэтому надо доставать в цикле пока все записи не достанутся.
- данные загружаются пачками по 200 записей, поэтому тоже делаем цикл для загрузки пачками по 200.
- self reference, циклические ссылки разруливаются немного сложнее, но тоже без проблем.
- ну и авторизацию для API замутить придется (либо либу использовать какую, хотя совсем не обязательно)


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

Вообще если кому интересно, то можно легко автоматизировать миграцию данных на pure python (как и на любом другом ЯП) и скрипт будет не таким сложным. И не надо будет заморачиваться с дополнительными ExternalID полями. Понятно что для одноразового использования и для двух связанных объектов это перебор, но если миграцию данных надо автоматизировать и связанных объектов будет десятки то мутить скрипт самое то.

Используем следующие SF API enpdoints:
1. Достаем данные - https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/dome_query.htm
2. Загружаем данные - https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/dome_composite_sobject_tree_flat.htm

[b]Вся магия кроется в referenceId[/b]. Переносим Id в attributes.referenceId и после загрузки на орг получаем мапу в таком виде: referenceId (он же Old Id) -> New Id (по второй ссылке можно глянуть живой пример ответа с мапой). Проходимся по child рекордам, заменяем все parent old ID на новый ID и загружаем. Повторяем процедуру для все child объектов вниз по иерархии.

Профит!

Из особенностей которые немного усложняют скрипт:
- данные достаются пачками до 2000 записей, поэтому надо доставать в цикле пока все записи не достанутся.
- данные загружаются пачками по 200 записей, поэтому тоже делаем цикл для загрузки пачками по 200.
- self reference, циклические ссылки разруливаются немного сложнее, но тоже без проблем.
- ну и авторизацию для API замутить придется (либо либу использовать какую, хотя совсем не обязательно)


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