Fazer upsert de dados do Clarizen com uma cadeia de operações no Jitterbit Design Studio
Introdução
Este padrão de integração usa uma cadeia de operações no Harmony Design Studio para fazer upsert de dados na sua instância do Clarizen conectada. Antes de começar, você já deve estar familiarizado com o funcionamento do Jitterbit, ter configurado um endpoint do Clarizen e ser capaz de usar as operações nativas de consulta, criação e atualização no conector do Clarizen do Design Studio.
Resumo
O objetivo de uma operação de upsert é atualizar registros que já existem e inserir registros que não existem. Embora a API REST do Clarizen não suporte explicitamente operações de upsert, o Jitterbit permite configurações simples e flexíveis de fluxos de trabalho de inserção/atualização.
Neste padrão, um campo de chave única é usado para determinar a existência de um registro procurando por um registro no Clarizen cujo campo de chave única tenha o mesmo valor. O campo de chave única deve ter um valor diferente para cada registro e ser o mesmo em ambos os sistemas. Qualquer campo que já mantenha essas propriedades pode ser usado, e se nenhum existir no objeto, um campo personalizado pode ser criado no Clarizen para armazenar os IDs de registro do sistema de origem.
O diagrama a seguir mostra o fluxo de trabalho generalizado de um upsert do Clarizen usando este padrão de design.

Especificamente, fazer upsert de registros no Clarizen requer manter pares (chave, valor) das chaves/valores únicos e corresponder esses aos IDs de registro do Clarizen. Depois, os registros podem ser separados em "criar" ou "atualizar" com base em se sua chave única tem um ID do Clarizen correspondente no armazenamento de chaves.
Existem várias maneiras de implementar o armazenamento de chaves e a separação de registros, com diferentes níveis de eficiência. Abaixo está a implementação que seguiremos neste padrão, que sacrifica eficiência pela simplicidade em certos lugares. Os números correspondem às etapas incluídas na próxima seção.

Implementação
As seções a seguir descrevem as principais etapas para implementar este padrão de design. Como exemplo, faremos upsert de dados de objeto de usuário existentes no Clarizen para nossos dados de objeto de cliente no Clarizen. Esta é a configuração final:

Etapa 1 - Obter dados de origem para fazer upsert

Primeiro, traga os dados que deseja usar para a operação de upsert usando a funcionalidade padrão do Jitterbit. Você pode usar uma variedade de fontes de dados.
Para este exemplo, consultaremos todos os funcionários existentes do objeto User na sua instância do Clarizen conectada e usaremos esses dados como origem para nosso upsert. Para o exemplo, configuramos nossos dados de origem da seguinte forma:
-
Crie uma nova operação de consulta do Clarizen para o objeto User e selecione todos os campos. A consulta é nomeada "Query Employees".
-
Crie uma operação a partir desta consulta (clique no botão Create Operation). A operação é nomeada "1. Obtain Source Data to be Upserted".
-
Passe os dados pela transformação sem alterações (clique com o botão direito em Response > Pass-Through). Você também pode configurar uma transformação normal para obter dados no formato que deseja usar.
-
Defina o destino como armazenamento temporário, nomeado "Employees" (clique duas vezes em Target > Create New Target; tipo: "Temporary Storage"; nome do arquivo: "employees").
-
Copie o destino "Employees" para uma fonte, também nomeada "Employees" (na árvore à esquerda, clique com o botão direito no destino específico > Copy to New Source). Isso será usado como a fonte para nossos dados de upsert na próxima operação.
-
Execute uma nova operação de transformação em caso de sucesso (clique com o botão direito no fundo da operação > On Success > Operation > Create New Operation > Transformation). Esta operação será usada na Etapa 2, a seguir.
Step 2 - Add unique keys to a dictionary

Um dicionário é usado neste padrão para manter os pares (chave única, ID do Clarizen). Nesta operação, inseriremos um script antes da fonte para inicializar um dicionário global e criar uma transformação para mapear o campo de chave única.
-
Dependendo de como você configurou sua fonte, você já deve ter uma nova operação em branco criada na Etapa 1. Caso contrário, crie uma nova operação de transformação (New Operation > Transformation). A operação é nomeada "2. Add Unique Keys to Dictionary."
-
Especifique a fonte dos seus dados. A fonte deve conter todos os registros a serem feitos upsert. No exemplo, usamos a fonte "Employees" criada na Etapa 1 (clique duas vezes em Source e selecione a fonte "Employees" existente).
-
Nenhum destino é necessário, portanto remova o destino da operação (clique com o botão direito em Target > Remove from Graph).
-
Insira um script antes da fonte (clique com o botão direito em Source > Insert Before This > Script) e crie um novo script (nomeado "Initialize the Dictionary") da seguinte forma:
<trans> $UpsertIdDict = Dict(); </trans> -
Crie uma nova transformação cujas estruturas de fonte e destino sejam iguais às dos seus dados (clique duas vezes em Transformation > Create New Transformation). A transformação no exemplo é nomeada "Map Unique Key Field."
- Para a fonte, selecione a mesma estrutura que seus dados de origem. No exemplo, nossa fonte é o resultado de uma consulta do Clarizen, portanto usamos "Clarizen Function Response." Para o destino, escolheremos "Text."
- Para a fonte, siga os prompts do assistente, no exemplo selecionando "Query" e a operação de consulta específica usada como fonte.
- Para o destino, criaremos manualmente uma nova estrutura que tenha um campo nela (Available File Format Definitions > Create New > Create Manually; em Define Segment Properties, clique em New e digite um nome de campo, por exemplo "ID"). No exemplo, o nome do formato de arquivo é "Unique Keys."
- Na transformação, itere sobre o campo de chave única mapeando-o no lado da fonte para o lado do destino (no exemplo, arraste e solte o campo User > Entity > "id" à esquerda para o campo "ID" à direita).
-
Modifique a transformação para que uma nova entrada seja adicionada ao dicionário com o campo de chave única como ID e '0' como valor. Para fazer isso, clique duas vezes no seu campo ID no lado do destino e digite o seguinte:
<trans> AddToDict($UpsertIdDict, Quote(<Your_Unique_Key>), 0) </trans>No exemplo, \<Your_Unique_Key> é substituído por OUTPUT\(User\)Entity.id$ selecionando o campo de chave única do lado da fonte.
<trans> AddToDict($UpsertIdDict, Quote(OUTPUT$User$Entity.id$), 0) </trans> -
Insira um novo script após a transformação que você acabou de criar (clique com o botão direito na transformação > Insert After This > Script) e crie um novo script chamado "Update Keystore." Por enquanto, deixaremos o script em branco. Isso será preenchido posteriormente durante a próxima etapa para criar um filtro de modo que apenas registros do Clarizen com chaves únicas que correspondam a uma no dicionário sejam consultados.
Step 3 - Query Clarizen for records with matching unique keys

Para popular o dicionário com IDs do Clarizen associados, neste padrão você precisará criar uma nova operação de consulta do Clarizen para o objeto que deseja fazer upsert. O ID e a chave única precisam ser consultados, e uma variável de projeto deve ser adicionada no final para incluir uma cláusula WHERE.
-
Crie uma nova operação de consulta do Clarizen para seu objeto (no exemplo, usamos o objeto Customer) com uma string de consulta no seguinte formato.
SELECT <Your_Unique_Key> FROM <Your_Object> Where <Your_Unique_Key> In [ClarizenWhereClause]No exemplo, usaremos um campo personalizado chamado "C_JB_External_Id" em nosso objeto Customer como nossa chave única, da seguinte forma:
SELECT C_JB_External_Id FROM Customer Where C_JB_External_Id In [ClarizenWhereClause]Nota
O [ClarizenWhereClause] é uma variável de projeto que definiremos mais tarde no script "Update Keystore".
-
Crie uma operação a partir desta consulta (clique no botão Create Operation). A operação é nomeada "3. Query Clarizen for Records with Matching Unique Keys."
-
Nenhum destino é necessário, então remova o destino da operação (clique com o botão direito em Target > Remove from Graph).
-
Crie uma nova transformação (clique duas vezes em Transformation > Create New Transformation). A transformação no exemplo é nomeada "Match Unique Keys."
- No exemplo, a origem já deve estar definida como a resposta da consulta do objeto. Para o destino, escolheremos "Text."
- Para a estrutura de destino, selecione o mesmo formato de arquivo criado durante a Etapa 2 (no exemplo, nomeado "Unique Keys").
- Na transformação, mapeie os campos de ID do lado da origem para o lado do destino (no exemplo, arraste e solte tanto o campo User > Entity > "id" quanto o campo personalizado "C_JB_External_Id" à esquerda para o campo "ID" à direita).
-
Modifique a transformação para escrever os IDs do Clarizen nos valores do dicionário para as chaves únicas correspondentes. Isso definirá sua chave única igual ao seu ID de objeto. Para fazer isso, clique duas vezes no seu campo de ID no lado do destino e digite o seguinte:
<trans> $UpsertIdDict[Quote(OUTPUT$<Your_Object>$Entity.<Your_Unique_Key>$)] = OUTPUT$<Your_Object>$Entity.id$; </trans>Lembre-se de que você pode clicar duas vezes nos campos sob OUTPUT no lado direito para obter os campos apropriados para sua chave única e objeto. O exemplo é lido da seguinte forma:
<trans> $UpsertIdDict[Quote(OUTPUT$Customer$Entity.C_JB_External_Id$)] = OUTPUT$Customer$Entity.id$; </trans> -
Em seguida, crie um novo script que construa uma cláusula IN a partir das chaves do dicionário. Isso pode ser criado fora da operação (na árvore à esquerda, clique com o botão direito em Scripts > New Script). O script no exemplo é nomeado "Construct InClause from Dict Keys." Cole o seguinte no script:
<trans> ArgumentList(Dictionary, start, end); keys = GetKeys(Dictionary); //keyIter = 0; inClause = ''; if(end > length(keys), //use length keys as condition while( start <length(keys)-1, inClause = inClause + keys[start] + ', '; start++;);, while( start < end , inClause = inClause + keys[start] + ', '; start++;); ); inClause + keys[start] </trans> -
Agora que o script da cláusula IN foi criado, podemos usá-lo dentro do script "Update Keystore" que foi criado no final da segunda operação na Etapa 2. Este script percorre seu dicionário de chaves e procura no Clarizen por um registro correspondente. Após a conclusão, ele executará as operações de atualização e inserção que configuraremos nas próximas etapas. Clique duas vezes neste script e digite o seguinte, substituindo os nomes de seus scripts e operações reais onde necessário.
<trans> //Update cache keys = GetKeys($UpsertIdDict); //WriteToOperationLog(keys); interval = 999; batch = 0; While(batch*interval < Length(keys), $ClarizenWhereClause = '(' + RunScript("<TAG>Scripts/Construct InClause From Dict Keys</TAG>",$UpsertIdDict, batch*interval, (batch + 1)*interval - 1) + ')'; WriteToOperationLog($ClarizenWhereClause); If(!RunOperation("<TAG>Operations/3. Query Clarizen for Records with Matching Unique Keys</TAG>",true), RaiseError(GetLastError()) ); batch ++; ); RunOperation("<TAG>Operations/4. Separate Records to Update; Update Records</TAG>",false); RunOperation("<TAG>Operations/5. Separate Records to Create; Insert Records</TAG>",false) </trans>Importante
A chamada síncrona
RunOperationdentro do loopWhileestá sujeita a um limite no nível do agente de chamadas síncronas feitas dentro de um único loopWhile(50por padrão). Cominterval = 999, este loop atinge esse limite em aproximadamente 50.000 chaves; para as cargas de 100.000 registros descritas em Optimization, o loop atinge o limite no meio do caminho e os lotes restantes não são consultados. Consulte a nota emRunOperationpara saber como configurar ou substituir esse limite, ou aumenteintervalpara reduzir o número de iterações de loop para grandes conjuntos de chaves.
Nota
A última parte deste script conecta as operações que serão criadas nos Passos 4 e 5. Você pode precisar voltar a este script no final para atualizar os nomes das operações, se necessário.
Passo 4 - Separar registros para atualizar e depois atualizar registros no Clarizen

Este passo filtra registros para uma operação de atualização no Clarizen e depois realiza a atualização dos registros na instância do Clarizen.
-
Crie uma nova operação de atualização do Clarizen para o objeto que deseja atualizar (no exemplo, o objeto Customer).
-
Especifique a fonte que contém todos os registros a serem inseridos ou atualizados. No exemplo, usamos a fonte "Employees" criada no Passo 1 (clique duas vezes em Source e selecione a fonte "Employees" existente).
-
Nenhum destino é necessário, então remova o destino da operação (clique com o botão direito em Target > Remove from Graph).
-
Crie uma nova transformação de requisição (clique duas vezes em Request > Create New Transformation). A transformação no exemplo é nomeada "Separate Records to Update."
-
Para a fonte, selecione a mesma estrutura dos dados de origem. No exemplo, nossa fonte é o resultado de uma consulta do Clarizen, então usamos "Clarizen Function Response." O destino deve ser definido como uma requisição para a operação de atualização.
-
Para a fonte do exemplo, siga os prompts do assistente, no exemplo selecionando "Query" e a operação de consulta específica usada como fonte. Se você tiver um tipo diferente de fonte, selecione as opções apropriadas.
-
Na transformação, crie uma condição na pasta do objeto de destino (no exemplo, clique com o botão direito na pasta Customer > Add condition). A condição deve retornar verdadeiro quando o registro for encontrado no dicionário e falso quando não for:
<trans> if($UpsertIdDict[Quote(OUTPUT$<Your_Object>$Entity.id$)]!='0', WriteToOperationLog('Found in Dict'); true, WriteToOperationLog('Not Found In Dict'); false) </trans>No exemplo, a condição é definida da seguinte forma:
<trans> if($UpsertIdDict[Quote(OUTPUT$User$Entity.id$)]!='0', WriteToOperationLog('Found in Dict'); true, WriteToOperationLog('Not Found In Dict'); false) </trans> -
Depois, mapeie o campo ID recuperando-o do dicionário usando a chave única. Ou seja, clique duas vezes no ID no lado do destino e insira o seguinte:
<trans> $UpsertIdDict[Quote(OUTPUT$<Your_Object>$Entity.id$)] </trans>No exemplo, isso é definido da seguinte forma:
<trans> $UpsertIdDict[Quote(OUTPUT$User$Entity.id$)] </trans> -
Prossiga mapeando os campos ID restantes, bem como quaisquer outros campos que devem ser mapeados ao atualizar. No exemplo, também mapeamos o campo User > Entity > "id" para o Customer > "C_JB_External_Id" (campo personalizado) à direita. No exemplo, o campo User > Entity > "DisplayName" também é mapeado para o campo Customer > "Name" à direita.
-
-
Para a transformação de resposta restante na operação, você pode passar os dados pela transformação sem alterações (clique com o botão direito em Response > Pass-Through).
-
Quando sua operação de atualização estiver concluída, verifique novamente o script "Update Keystore" descrito no final do Passo 3 para garantir que esta operação esteja incluída para ser executada dentro do script.
Passo 5 - Separar registros para criar e depois inserir registros no Clarizen

Este passo filtra registros para uma operação de criação no Clarizen e depois realiza a inserção dos registros na instância do Clarizen.
-
Crie uma nova operação de criação do Clarizen para o objeto no qual deseja inserir dados (no exemplo, o objeto Customer).
-
Especifique a fonte que contém todos os registros a serem inseridos ou atualizados. No exemplo, usamos a fonte "Employees" criada no Passo 1 (clique duas vezes em Source e selecione a fonte "Employees" existente).
-
Nenhum destino é necessário, então remova o destino da operação (clique com o botão direito em Target > Remove from Graph).
-
Crie uma nova transformação de requisição (clique duas vezes em Request > Create New Transformation). A transformação no exemplo é nomeada "Separate Records to Create."
-
Para a origem, selecione a mesma estrutura dos seus dados de origem. No exemplo, nossa origem é o resultado de uma consulta Clarizen, então usamos "Clarizen Function Response." O destino deve ser definido como uma requisição para a operação de criação.
-
Para a origem do exemplo, siga os prompts do assistente, no exemplo selecionando "Query" e a operação de consulta específica usada como origem. Se você tiver um tipo diferente de origem, selecione as opções apropriadas.
-
Na transformação, crie uma condição na pasta do objeto de destino (no exemplo clique com o botão direito na pasta Customer > Add condition). A condição deve retornar false quando o registro for encontrado no dicionário e true quando não for:
<trans> if($UpsertIdDict[Quote(OUTPUT$<Your_Object>$Entity.id$)]=='0', WriteToOperationLog('Not Found in Dict. Creating CZ customer'); true, WriteToOperationLog('Found In Dict. Customer already exists in CZ'); false) </trans>No exemplo, a condição é definida da seguinte forma:
<trans> if($UpsertIdDict[Quote(OUTPUT$User$Entity.id$)]=='0', WriteToOperationLog('Not Found in Dict. Creating CZ customer'); true, WriteToOperationLog('Found In Dict. Customer already exists in CZ'); false) </trans> -
Prossiga mapeando os campos de ID restantes, bem como quaisquer outros campos que devam ser mapeados ao atualizar. No exemplo, também mapeamos o campo User > Entity > "id" para Customer > "C_JB_External_Id" (campo personalizado) à direita. No exemplo, o campo User > Entity > "DisplayName" também é mapeado para o campo Customer > "Name" à direita.
-
-
Para a transformação de resposta restante na operação, você pode passar os dados pela transformação sem alterações (clique com o botão direito em Response > Pass-Through).
-
Quando sua operação de criação estiver concluída, verifique novamente o script "Update Keystore" descrito no final da Etapa 3 para garantir que essa operação esteja incluída para ser executada dentro do script.
Otimização
O padrão de design apresentado acima usa um dicionário para manter chaves únicas com seus IDs Clarizen associados para fins de simplicidade.
Isso é suficiente para muitos casos de uso, mas como o dicionário não é persistido, o Clarizen deve ser consultado toda vez para criar o keystore. Isso adicionará pelo menos 1 uso de API extra por registro inserido ou atualizado.
Como uma consulta em massa pode ser usada para consultar 100.000 registros por chamada, a despesa geralmente é negligenciável para grandes carregamentos de dados. No entanto, para aplicações em tempo real de alta frequência, isso pode rapidamente se tornar uma adição cara.
Uma alternativa é usar o cache em nuvem do Jitterbit para armazenar esses IDs. Existem algumas complexidades adicionadas ao usar o cache em nuvem; como permite apenas 250 leituras/escritas por segundo, o implementador deve lidar com o caso em que a leitura ou escrita falha.
Outras alternativas são usar camadas de persistência externa para manter o keystore ou usar armazenamento local se estiver usando um agente privado.