Upsert Clarizen Data com uma Cadeia de Operações
Introdução
Este padrão de integração usa uma cadeia de operações dentro do Harmony Design Studio para inserir dados em sua instância do Clarizen conectada. Antes de começar, você já deve estar familiarizado com o funcionamento do Jitterbit, configure um endpoint Clarizen e ser capaz de usar a consultar, criar e atualizar operações dentro do Design Studio Conector Clarizen.
Resumo
O objetivo de uma operação 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 upsert, o Jitterbit permite configurações simples e flexíveis de workflows de inserção/atualização.
Nesse padrão, um campo-chave exclusivo é usado para determinar a existência de um registro, procurando um registro no Clarizen cujo campo-chave exclusivo tenha o mesmo valor. O campo 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 não existir nenhum 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 workflow generalizado de um upsert do Clarizen usando esse padrão de design.
Especificamente, a atualização de registros no Clarizen requer a manutenção de pares (chave, valor) da chave/valores exclusivos e a correspondência desses com os IDs de registro do Clarizen. Em seguida, os registros podem ser separados em "criar" ou "atualizar" com base no fato de sua chave exclusiva ter um ID Clarizen correspondente no repositório de chaves.
Existem inúmeras maneiras de implementar o repositório de chaves e a separação de registros, com níveis variados de eficiência. Abaixo está a implementação que seguiremos neste padrão, que sacrifica a eficiência pela simplicidade em determinados locais. 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 esse padrão de design. Como exemplo, iremos atualizar os dados de objeto Usuário existentes no Clarizen para nossos dados de objeto Cliente no Clarizen. Esta é a configuração final:
Etapa 1 - Obtenha os Dados de Origem a Serem Atualizados
Primeiro, traga os dados que deseja usar para a operação upsert usando a funcionalidade Jitterbit padrão. Você pode usar uma variedade de fontes De dados.
Para este exemplo, vamos consultar todos os funcionários existentes do objeto User em nossa instância conectada do Clarizen e, em seguida, usar esses dados como fonte para nosso upsert. Para o exemplo, configuramos nossos dados de origem da seguinte maneira:
-
Crie uma nova operação de consultar do Clarizen para o objeto Usuário e selecione todos os campos. A consultar é denominada "Consulta Funcionários".
-
Crie uma operação a partir desta consultar (clique no botão Create Operation). A operação é denominada "1. Obter dados de origem para serem atualizados".
-
Passe os dados pela transformação sem nenhuma alteração (clique com o botão direito do mouse em Response > Pass-Through). Você também pode configurar uma transformação normal para obter dados no formato que gostaria de usar.
-
Defina o destino como armazenamento temporário, denominado "Empregados" (clique duas vezes em Destino > Criar novo destino; digite: "Armazenamento temporário"; nome do arquivo: "funcionários").
-
Copie o destino "Funcionários" para uma origem, também denominada "Funcionários" (na árvore à esquerda, clique com o botão direito do mouse no destino específico > Copiar para nova origem). Isso será usado como fonte para nossos dados upsert na próxima operação.
-
Execute uma nova operação de transformação após o sucesso (clique com o botão direito do mouse no fundo da operação > On Success > Operation > Create New Operation > Transformação). Esta operação será utilizada no Passo 2, a seguir.
Etapa 2 - Adicionar Chaves Exclusivas a um Dicionário
Um dicionário é usado neste padrão para manter os pares (chave única, Clarizen ID). Nesta operação, vamos inserir 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 a partir da Etapa 1. Caso contrário, crie uma nova operação de transformação (Nova Operação > Transformação). A operação é denominada "2. Adicionar chaves exclusivas ao dicionário".
-
Especifique a fonte de seus dados. A fonte deve conter todos os registros a serem atualizados. No exemplo, usamos a origem "Funcionários" criada na Etapa 1 (clique duas vezes em Fonte e selecione a origem "Funcionários" existente).
-
Nenhum destino é necessário, então remova o destino da operação (clique com o botão direito do mouse em Destino > Remover do Gráfico).
-
Insira um script antes da fonte (clique com o botão direito do mouse em Source > Insert Before This > Script) e crie um novo script (chamado "Initialize the Dictionary") como segue:
<trans> $UpsertIdDict = Dict(); </trans>
-
Crie uma nova transformação cujas estruturas de origem e destino sejam as mesmas de seus dados (clique duas vezes em Transformação > Create New Transformação). A transformação no exemplo é denominada "Map Unique Key Field".
- Para a fonte, selecione a mesma estrutura dos seus dados de origem. No exemplo, nossa fonte é o resultado de uma consultar Clarizen, então usamos "Resposta da função Clarizen ". Para o destino, escolheremos "Texto".
- Para a fonte, siga os prompts do assistente, no exemplo selecionando "Consulta" e a operação de consultar específica usada como fonte.
- Para o destino, criaremos manualmente uma nova estrutura com um campo (Definições de formato de arquivo disponível > Criar novo > Criar manualmente; em Defina as propriedades do segmento, clique em Novo 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 exclusiva mapeando-o no lado de origem para o lado de destino (no exemplo, arraste e solte o campo Usuário > Entidade > "id" à esquerda para o campo "ID" à direita).
-
Modifique a transformação para que uma nova entrada seja incluída no dicionário com o campo de chave exclusivo como o ID e '0' como o valor. Para fazer isso, clique duas vezes no seu campo de 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 exclusiva do lado da fonte.
<trans> AddToDict($UpsertIdDict, Quote(OUTPUT$User$Entity.id$), 0) </trans>
-
Insira um novo script depois da transformação que você acabou de criar (clique com o botão direito do mouse na transformação > Insert After This > Script) e crie um novo script chamado "Update Keystore". Por enquanto vamos deixar o script em branco. Isso será preenchido posteriormente durante a próxima etapa para criar um filtro para que apenas os registros do Clarizen com chaves exclusivas que correspondam a uma no dicionário sejam consultados.
Etapa 3 - Consultar Clarizen para Registros com Chaves Exclusivas Correspondentes
Para preencher o dicionário com IDs do Clarizen associados, neste padrão você precisará criar uma nova operação de consultar do Clarizen para o objeto que deseja atualizar. O ID e a chave exclusiva 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 consultar do Clarizen para seu objeto (no exemplo, usamos o objeto Customer) com uma consultar string 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 Cliente como nossa chave exclusiva, conforme a seguir:
SELECT C_JB_External_Id FROM Customer Where C_JB_External_Id In [ClarizenWhereClause]
Nota
O [ClarizenWhereClause] é uma variável de projeto que definiremos posteriormente no script"Update Keystore".
-
Crie uma operação a partir desta consultar (clique no botão Create Operation). A operação é denominada "3. Consultar Clarizen para registros com chaves exclusivas correspondentes".
-
Nenhum destino é necessário, então remova o destino da operação (clique com o botão direito do mouse em Destino > Remover do Gráfico).
-
Crie uma nova transformação (clique duas vezes em Transformação > Create New Transformação). A transformação no exemplo é denominada "Match Unique Keys".
- No exemplo, a fonte já deve estar definida como a resposta da consultar do objeto. Para o destino, escolheremos "Texto".
- Para a estrutura de destino, selecione o mesmo formato de arquivo criado durante a Etapa 2 (no exemplo, denominado "Chaves exclusivas").
- Na transformação, mapeie os campos de ID do lado de origem para o lado de destino (no exemplo, arraste e solte o campo Usuário > Entidade > "id" e o campo personalizado "C_JB_External_Id" à esquerda ao campo "ID" à direita).
-
Modifique a transformação para gravar os IDs do Clarizen nos valores do dicionário para as chaves exclusivas correspondentes. Isso definirá sua chave exclusiva 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 em OUTPUT no lado direito para obter os campos apropriados para sua chave e objeto exclusivos. O exemplo diz o seguinte:
<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 do mouse em Scripts > Novo Script). O script no exemplo é denominado "Construir InClause a partir de chaves de dicionário". 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 no script "Update Keystore" que foi criado no final da segunda operação na Etapa 2. Esse script percorre seu dicionário de chaves e procura no Clarizen um registro correspondente. Depois de concluído, ele executará as operações de atualização e inserção que configuraremos nas próximas etapas. Clique duas vezes neste script e insira o seguinte, substituindo os nomes de seus scripts e operações reais quando 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>
Nota
A última parte deste script conecta as operações que serão criadas a seguir nas Etapas 4 e 5. Talvez seja necessário voltar a este script no final para atualizar quaisquer nomes de operação, se necessário.
Etapa 4 - Separe os Registros para Atualizar E, em Seguida, Atualize os Registros no Clarizen
Esta etapa filtra os registros para uma operação de atualização do Clarizen e, em seguida, executa 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 Cliente).
-
Especifique a origem que contém todos os registros a serem atualizados. No exemplo, usamos a origem "Funcionários" criada na Etapa 1 (clique duas vezes em Fonte e selecione a origem "Funcionários" existente).
-
Nenhum destino é necessário, então remova o destino da operação (clique com o botão direito do mouse em Destino > Remover do Gráfico).
-
Crie uma nova transformação de solicitação (clique duas vezes em Request > Create New Transformação). A transformação no exemplo é chamada de "Registros Separados para Atualizar".
-
Para a fonte, selecione a mesma estrutura dos seus dados de origem. No exemplo, nossa fonte é o resultado de uma consultar Clarizen, então usamos "Resposta da função Clarizen ". O destino deve ser definido como uma solicitação para a operação de atualização.
-
Para a fonte de exemplo, siga os prompts do assistente, no exemplo selecionando "Consulta" e a operação de consultar 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 do mouse na pasta Cliente > Adicionar condição). A condição deve retornar true quando o registro for encontrado no dicionário e false 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>
-
Em seguida, mapeie o campo ID recuperando-o do dicionário usando a chave exclusiva. Ou seja, clique duas vezes no ID no lado de 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 com o mapeamento de quaisquer campos de ID restantes, bem como quaisquer outros campos que devem ser mapeados durante a atualização. No exemplo, também mapeamos o campo Usuário > Entidade > "id" para o campo Cliente > "C_JB_External_Id" (campo personalizado) à direita. No exemplo, o campo Usuário > Entidade > "DisplayName" também é mapeado para o campo Cliente > "Nome" à direita.
-
-
Para a transformação de resposta restante na operação, você pode passar os dados pela transformação sem nenhuma alteração (clique com o botão direito do mouse em Response > Pass-Through).
-
Quando a operação de atualização estiver concluída, verifique novamente o script "Update Keystore" descrito no final da Etapa 3 para garantir que esta operação seja incluída para execução no script.
Etapa 5 - Separe os Registros para Criar e Insira os Registros no Clarizen
Esta etapa filtra registros para uma operação de criação do Clarizen e, em seguida, executa a inserção de registros na instância do Clarizen.
-
Crie uma nova operação de criação do Clarizen para o objeto no qual você deseja inserir dados (no exemplo, o objeto Cliente).
-
Especifique a origem que contém todos os registros a serem atualizados. No exemplo, usamos a origem "Funcionários" criada na Etapa 1 (clique duas vezes em Fonte e selecione a origem "Funcionários" existente).
-
Nenhum destino é necessário, então remova o destino da operação (clique com o botão direito do mouse em Destino > Remover do gráfico).
-
Crie uma nova transformação de solicitação (clique duas vezes em Request > Create New Transformação). A transformação no exemplo é chamada de "Registros Separados para Criar".
-
Para a fonte, selecione a mesma estrutura dos seus dados de origem. No exemplo, nossa fonte é o resultado de uma consultar Clarizen, então usamos "Resposta da função Clarizen ". O destino deve ser definido como uma solicitação para a operação de criação.
-
Para a fonte de exemplo, siga os prompts do assistente, no exemplo selecionando "Consulta" e a operação de consultar 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 do mouse na pasta Cliente > Adicionar condição). 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 com o mapeamento de quaisquer campos de ID restantes, bem como quaisquer outros campos que devem ser mapeados durante a atualização. No exemplo, também mapeamos o campo Usuário > Entidade > "id" para o campo Cliente > "C_JB_External_Id" (campo personalizado) à direita. No exemplo, o campo Usuário > Entidade > "DisplayName" também é mapeado para o campo Cliente > "Nome" à direita.
-
-
Para a transformação de resposta restante na operação, você pode passar os dados pela transformação sem nenhuma alteração (clique com o botão direito do mouse em Response > Pass-Through).
-
Quando a operação de criação estiver concluída, verifique novamente o script "Atualizar Keystore" descrito no final da Etapa 3 para garantir que essa operação seja incluída para execução no script.
Otimização
O padrão de design apresentado acima usa um dicionário para manter chaves exclusivas com seus IDs Clarizen associados para fins de simplicidade.
Isso é suficiente para muitos casos de uso, mas como o dicionário não persiste, o Clarizen deve ser consultado todas as vezes para criar o repositório de chaves. Isso adicionará pelo menos 1 uso extra de API por registro atualizado.
Como uma consultar em massa pode ser usada para consultar 100.000 registros por chamada, a despesa geralmente é insignificante para grandes cargas 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 da nuvem do Jitterbit para armazenar esses IDs. Existem algumas complexidades adicionais no uso do cache na nuvem; uma vez que permite apenas 250 leituras/gravações por segundo, o implementador deve lidar com o caso de falha na leitura ou gravação.
Outras alternativas são usar camadas de persistência externas para manter o repositório de chaves ou usar armazenamento local se estiver usando um Agente Privado.