Aaron Benton é um arquiteto experiente, especializado em soluções criativas para desenvolver aplicativos móveis inovadores. Ele tem mais de 10 anos de experiência em desenvolvimento de pilha completa, incluindo ColdFusion, SQL, NoSQL, JavaScript, HTML e CSS. Atualmente, Aaron é Arquiteto de Aplicativos da Shop.com em Greensboro, Carolina do Norte, e é um Campeão da comunidade do Couchbase.

FakeIt Série 2 de 5: Dados compartilhados e dependências
Em FakeIt Série 1 de 5: Geração de dados falsos aprendemos que a FakeIt pode gerar uma grande quantidade de dados aleatórios com base em um único arquivo YAML e enviar os resultados para vários formatos e destinos, incluindo o Couchbase Server. Hoje vamos explorar o que torna a FakeIt realmente única e poderosa no mundo da geração de dados.
Há muitos geradores de dados aleatórios disponíveis, um simples Pesquisa do Google lhe darão mais do que o suficiente para escolher. No entanto, quase todos eles têm a mesma falha frustrante, que é o fato de só poderem lidar com um único modelo. Raramente, como desenvolvedores, temos o luxo de lidar com um único modelo; na maioria das vezes, estamos desenvolvendo vários modelos para nossos projetos. É nesse ponto que o FakeIt se destaca: ele permite vários modelos e que esses modelos tenham dependências.
Vamos dar uma olhada nos possíveis modelos que teremos em nosso aplicativo de comércio eletrônico:
- Usuários
- Produtos
- Carrinho
- Pedidos
- Comentários
Usuários, o primeiro modelo que definimos, não tem nenhuma dependência, e o mesmo pode ser dito do modelo Produtos, que definiremos a seguir. No entanto, seria lógico dizer que o nosso modelo Orders dependeria dos modelos Users e Products. Se realmente quisermos dados de teste, os documentos criados pelo nosso modelo Orders deverão ser os dados aleatórios reais gerados pelos modelos Users e Products.
Modelo de produtos
Antes de analisarmos como as dependências de modelo funcionam na FakeIt, vamos definir como será o nosso modelo de produtos.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
name: Products type: object key: _id properties: _id: type: string description: The document id data: post_build: `product_${this.product_id}` doc_type: type: string description: The document type data: value: product product_id: type: string description: Unique identifier representing a specific product data: build: faker.random.uuid() price: type: double description: The product price data: build: chance.floating({ min: 0, max: 150, fixed: 2 }) sale_price: type: double description: The product price data: post_build: | let sale_price = 0; if (chance.bool({ likelihood: 30 })) { sale_price = chance.floating({ min: 0, max: this.price * chance.floating({ min: 0, max: 0.99, fixed: 2 }), fixed: 2 }); } return sale_price; display_name: type: string description: Display name of product. data: build: faker.commerce.productName() short_description: type: string description: Description of product. data: build: faker.lorem.paragraphs(1) long_description: type: string description: Description of product. data: build: faker.lorem.paragraphs(5) keywords: type: array description: An array of keywords items: type: string data: min: 0 max: 10 build: faker.random.word() availability: type: string description: The availability status of the product data: build: | let availability = 'In-Stock'; if (chance.bool({ likelihood: 40 })) { availability = faker.random.arrayElement([ 'Preorder', 'Out of Stock', 'Discontinued' ]); } return availability; availability_date: type: integer description: An epoch time of when the product is available data: build: faker.date.recent() post_build: new Date(this.availability_date).getTime() product_slug: type: string description: The URL friendly version of the product name data: post_build: faker.helpers.slugify(this.display_name).toLowerCase() category: type: string description: Category for the Product data: build: faker.commerce.department() category_slug: type: string description: The URL friendly version of the category name data: post_build: faker.helpers.slugify(this.category).toLowerCase() image: type: string description: Image URL representing the product. data: build: faker.image.image() alternate_images: type: array description: An array of alternate images for the product items: type: string data: min: 0 max: 4 build: faker.image.image() |
Esse modelo é um pouco mais complexo do que o modelo anterior de Usuários. Vamos examinar algumas dessas propriedades em mais detalhes:
- _id: Esse valor está sendo definido depois que cada propriedade do documento foi criada e está disponível para a função de pós-compilação. Esse contexto é o do documento atual que está sendo gerado
- preço de venda: Para isso, é necessário definir uma chance de preço de venda e, se houver um preço de venda, garantir que o valor seja menor do que o da propriedade de preço
- palavras-chave: É uma matriz. Definido de forma semelhante ao Swagger, definimos nossos itens de matriz e como queremos que eles sejam construídos usando as funções build / post_build. Além disso, podemos definir os valores mínimo e máximo, e o FakeIt gerará um número aleatório de elementos de matriz entre esses valores. Há também uma propriedade fixa que pode ser usada para gerar um número definido de elementos de matriz.
Agora que construímos nosso modelo de produtos, vamos gerar alguns dados aleatórios e enviá-los ao console para ver como eles se parecem usando o comando:
|
1 |
fakeit console models/products.yaml |

Modelo de pedidos
Para nosso projeto, já definimos os seguintes modelos:
- users.yaml
- produtos.yaml
Vamos começar definindo o modelo Orders sem nenhuma propriedade e especificando suas dependências:
|
1 2 3 4 5 6 7 8 |
name: Orders type: object key: _id data: dependencies: - products.yaml - users.yaml properties: |
Definimos duas dependências para o nosso modelo Orders e as referenciamos pelo nome do arquivo. Como todos os nossos modelos são armazenados no mesmo diretório, não há motivo para especificar o caminho completo. No tempo de execução, a FakeIt analisará primeiro todos os modelos antes de tentar gerar documentos e determinará uma ordem de execução com base em cada uma das dependências dos modelos (se houver).
Cada uma das funções de compilação em um modelo FakeIt é um corpo de função, com os seguintes argumentos passados a ele.
|
1 2 3 |
function (documents, globals, inputs, faker, chance, document_index, require) { return faker.internet.userName(); } |
Depois que a ordem de execução é estabelecida, cada uma das dependências é salva na memória e disponibilizada para o modelo dependente por meio do argumento documents. Esse argumento é um objeto que contém uma chave para cada modelo, cujo valor é uma matriz de cada documento que foi gerado. Para o nosso exemplo da propriedade documents, a aparência será semelhante a esta:
|
1 2 3 4 5 6 7 8 |
{ "Users": [ ... ], "Products": [ ... ] } |
Podemos tirar proveito disso para recuperar documentos aleatórios de produtos e usuários, atribuindo suas propriedades às propriedades do nosso modelo Orders. Por exemplo, podemos recuperar um user_id aleatório dos documentos gerados pelo modelo Users e atribuí-lo ao user_id do modelo Orders por meio de uma função de compilação
|
1 2 3 4 5 |
user_id: type: integer description: The user_id that placed the order data: build: faker.random.arrayElement(documents.Users).user_id; |
Vamos definir como será o restante do nosso modelo de Orders:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 |
name: Orders type: object key: _id data: dependencies: - products.yaml - users.yaml properties: _id: type: string description: The document id data: post_build: `order_${this.order_id}` doc_type: type: string description: The document type data: value: "order" order_id: type: integer description: The order_id data: build: document_index + 1 user_id: type: integer description: The user_id that placed the order data: build: faker.random.arrayElement(documents.Users).user_id; order_date: type: integer description: An epoch time of when the order was placed data: build: new Date(faker.date.past()).getTime() order_status: type: string description: The status of the order data: build: faker.random.arrayElement([ 'Pending', 'Processing', 'Cancelled', 'Shipped' ]) billing_name: type: string description: The name of the person the order is to be billed to data: build: `${faker.name.firstName()} ${faker.name.lastName()}` billing_phone: type: string description: The billing phone data: build: faker.phone.phoneNumber().replace(/x[0-9]+$/, '') billing_email: type: string description: The billing email data: build: faker.internet.email() billing_address_1: type: string description: The billing address 1 data: build: `${faker.address.streetAddress()} ${faker.address.streetSuffix()}` billing_address_2: type: string description: The billing address 2 data: build: chance.bool({ likelihood: 50 }) ? faker.address.secondaryAddress() : null billing_locality: type: string description: The billing city data: build: faker.address.city() billing_region: type: string description: The billing region, city, province data: build: faker.address.stateAbbr() billing_postal_code: type: string description: The billing zip code / postal code data: build: faker.address.zipCode() billing_country: type: string description: The billing region, city, province data: value: US shipping_name: type: string description: The name of the person the order is to be billed to data: build: `${faker.name.firstName()} ${faker.name.lastName()}` shipping_address_1: type: string description: The shipping address 1 data: build: `${faker.address.streetAddress()} ${faker.address.streetSuffix()}` shipping_address_2: type: string description: The shipping address 2 data: build: chance.bool({ likelihood: 50 }) ? faker.address.secondaryAddress() : null shipping_locality: type: string description: The shipping city data: build: faker.address.city() shipping_region: type: string description: The shipping region, city, province data: build: faker.address.stateAbbr() shipping_postal_code: type: string description: The shipping zip code / postal code data: build: faker.address.zipCode() shipping_country: type: string description: The shipping region, city, province data: value: US shipping_method: type: string description: The shipping method data: build: faker.random.arrayElement([ 'USPS', 'UPS Standard', 'UPS Ground', 'UPS 2nd Day Air', 'UPS Next Day Air', 'FedEx Ground', 'FedEx 2Day Air', 'FedEx Standard Overnight' ]); shipping_total: type: double description: The shipping total data: build: chance.dollar({ min: 10, max: 50 }).slice(1) tax: type: double description: The tax total data: build: chance.dollar({ min: 2, max: 10 }).slice(1) line_items: type: array description: The products that were ordered items: type: string data: min: 1 max: 5 build: | const random = faker.random.arrayElement(documents.Products); const product = { product_id: random.product_id, display_name: random.display_name, short_description: random.short_description, image: random.image, price: random.sale_price || random.price, qty: faker.random.number({ min: 1, max: 5 }), }; product.sub_total = product.qty * product.price; return product; grand_total: type: double description: The grand total of the order data: post_build: | let total = this.tax + this.shipping_total; for (let i = 0; i < this.line_items.length; i++) { total += this.line_items[i].sub_total; } return chance.dollar({ min: total, max: total }).slice(1); |
E envie-o para o console usando o comando:
|
1 |
fakeit console models/orders.yaml |

Como você pode ver na saída do console, os documentos foram gerados para os modelos Usuários e Produtos, e esses documentos foram disponibilizados para o modelo Pedidos. No entanto, eles foram excluídos da saída porque tudo o que foi solicitado para saída foi o modelo Orders.
Agora que definimos três modelos com dependências (Usuários, Produtos e Pedidos), precisamos ser capazes de gerar vários documentos para cada um deles e enviá-los ao Couchbase Server. Até este ponto, especificamos o número de documentos a serem gerados por meio do argumento de linha de comando -count. Podemos especificar o número de documentos ou um intervalo de documentos usando a propriedade data: na raiz do modelo.
|
1 2 3 4 5 6 7 8 |
users.yaml name: Users type: object key: _id data: min: 1000 max: 2000 |
|
1 2 3 4 5 6 7 8 |
products.yaml name: Products type: object key: _id data: min: 4000 max: 5000 |
|
1 2 3 4 5 6 7 8 9 10 11 |
orders.yaml name: Orders type: object key: _id data: dependencies: - products.yaml - users.yaml min: 5000 max: 6000 |
Agora podemos gerar conjuntos aleatórios de modelos de documentos relacionados e enviar esses documentos diretamente para o Couchbase Server usando o comando:
|
1 |
fakeit couchbase --server 127.0.0.1 --bucket ecommerce --verbose models/ |

Conclusão
Vimos, por meio de três modelos simples do FakeIt YAML, como podemos criar dependências de modelos, permitindo que dados gerados aleatoriamente sejam relacionados entre modelos e transmitidos para o Couchbase Server. Também vimos como podemos especificar o número de documentos a serem gerados por modelo usando a propriedade data: na raiz de um modelo.
Esses modelos podem ser armazenados no repositório de projetos, ocupando muito pouco espaço e permitindo que os desenvolvedores gerem as mesmas estruturas de dados com dados completamente diferentes. Outra vantagem de poder gerar documentos por meio de relacionamentos de vários modelos é explorar diferentes modelos de documentos e ver o desempenho deles com várias consultas N1QL.
Próximo
- Série FakeIt 3 de 5: Modelos Lean por meio de definições
- FakeIt Série 4 de 5: Trabalhando com dados existentes
- FakeIt Series 5 de 5: Desenvolvimento móvel rápido com o Sync-Gateway
Anterior
- FakeIt Série 1 de 5: Geração de dados falsos
Esta postagem faz parte do Programa de Redação da Comunidade Couchbase
[...] em nosso post anterior FakeIt Series 2 of 5: Shared Data and Dependencies, vimos como criar dependências de vários modelos com o FakeIt. Hoje, [...]
[...] até agora, em nossa série FakeIt, vimos como podemos gerar dados falsos, compartilhar dados e dependências e usar definições para modelos menores. Hoje vamos dar uma olhada no último recurso importante do [...]