---
term: 'Modelagem de Dados'
seoTitle: 'O que é Modelagem de Dados? Relacionamentos, Pointers e Relations'
headline: 'O que é modelagem de dados?'
slug: modelagem-de-dados
category: database
shortDefinition: 'A modelagem de dados é o processo de mapear entidades, atributos e relacionamentos antes de decidir como o banco de dados vai armazená-los.'
relatedTerms:
  - database-schema
  - relational-queries-document-databases
  - n-plus-one-query-problem
  - auto-generated-database-apis
contrastsWith:
  - database-schema
faq:
  - question: 'O que é modelagem de dados?'
    answer: 'O processo de mapear a informação de uma aplicação — suas entidades, os atributos delas e os relacionamentos entre elas — num design que um banco de dados consegue armazenar. Ele costuma atravessar três níveis de detalhe: um modelo conceitual nomeando as entidades, um modelo lógico adicionando atributos e chaves, e um modelo físico se comprometendo com tabelas, colunas e índices num motor específico.'
  - question: 'Quais são os três tipos de modelos de dados?'
    answer: 'Conceitual, lógico e físico — o mesmo design em zoom crescente. O conceitual responde "o que existe e como se relaciona" para o lado de negócio. O lógico adiciona atributos, tipos e chaves sem se prender a tecnologia. O físico se compromete com um motor real: tabelas ou coleções, índices, constraints. Cada nível é o anterior mais decisões.'
  - question: 'O que é um relacionamento um-para-muitos?'
    answer: 'Um registro pai relacionado a muitos filhos, cada filho pertencendo a exatamente um pai — um cliente e seus pedidos, um autor e seus livros. É o relacionamento mais comum de qualquer schema. Bancos relacionais o implementam com uma chave estrangeira no lado "muitos"; bancos de documentos usam um array embutido para conjuntos pequenos e limitados, ou um pointer para o pai em todo o resto.'
  - question: 'O que é um relacionamento muitos-para-muitos e por que ele precisa de tabela de junção?'
    answer: 'Os dois lados se relacionam com muitos do outro — alunos e cursos, livros e gêneros. Uma coluna de chave estrangeira só consegue apontar para uma linha, então bancos relacionais decompõem o muitos-para-muitos em dois um-para-muitos através de uma tabela de junção com as duas chaves (e, muitas vezes, atributos da relação, como a data de matrícula). Bancos de documentos dispensam a junção: arrays de referências, ou um tipo dedicado de relação, carregam a aresta diretamente.'
  - question: 'Como diferenciar um-para-muitos de muitos-para-muitos?'
    answer: 'Faça a pergunta de posse nos dois sentidos. "Um autor pode ter muitos livros?" Sim. "Um livro pode ter muitos autores?" Se não — um-para-muitos, chave estrangeira no livro. Se sim — muitos-para-muitos, tabela de junção ou Relation. Errar aqui é o erro clássico de modelagem: um muitos-para-muitos modelado como um-para-muitos ou duplica linhas ou perde arestas em silêncio.'
  - question: 'O que é cardinalidade em um diagrama ER?'
    answer: 'Quantas instâncias de uma entidade podem se relacionar com instâncias de outra — um-para-um, um-para-muitos, muitos-para-muitos. Os diagramas expressam isso em uma de três notações: números e letras nas linhas de conexão, os símbolos pé-de-galinha (uma barra para "um", um garfo de três pontas para "muitos"), ou faixas de multiplicidade como 1 e asterisco. Mesma semântica, convenções de desenho diferentes.'
  - question: 'Como bancos de documentos modelam relacionamentos sem chaves estrangeiras?'
    answer: 'Com três ferramentas: embutir (aninhar os dados relacionados dentro do documento pai — certo quando são lidos juntos, têm um dono só e tamanho limitado), pointers ou referências (guardar o ID do documento relacionado como campo tipado — certo para ciclos de vida independentes e alta cardinalidade), e objetos Relation ou arrays de IDs para muitos-para-muitos. A regra-guia troca a normalização pelos padrões de acesso: dados lidos juntos devem viver juntos.'
  - question: 'Quais são os erros mais comuns de modelagem de dados?'
    answer: 'Um top cinco estável: modelar muitos-para-muitos como um-para-muitos; esquecer índices nos campos de chave estrangeira e de pointer (todo join e lookup paga por isso); arrays embutidos sem limite de crescimento em schemas de documento; denormalização prematura antes de qualquer query se provar lenta; e modelar só a partir das entidades, sem listar as queries — os padrões de acesso — que o modelo precisa servir.'
codeLanguages: [javascript, dart, swift, kotlin]
externalAuthorities:
  - name: 'MongoDB — Embedding vs. References'
    url: 'https://www.mongodb.com/docs/manual/data-modeling/concepts/embedding-vs-references/'
  - name: 'Many-to-many data model (Wikipedia)'
    url: 'https://en.wikipedia.org/wiki/Many-to-many_(data_model)'
  - name: 'Entity–relationship model (Wikipedia)'
    url: 'https://en.wikipedia.org/wiki/Entity%E2%80%93relationship_model'
  - name: 'SDK relational data guide'
    url: 'https://docs.parseplatform.org/js/guide/#relational-data'
cta:
  title: 'Modele uma vez, consulte em todo lugar'
  text: 'No Back4app, o modelo é o backend: classes no dashboard, Pointers para um-para-muitos, Relations para muitos-para-muitos — e cada aresta que você declara vira consultável na hora via REST, GraphQL e SDKs gerados automaticamente, com include() embutido.'
  linkText: 'Comece grátis'
  linkUrl: 'https://www.back4app.com/signup'
author: 'Back4app Engineering'
publishedDate: '2026-08-21'
translationKey: data-modeling
---

**A modelagem de dados é o processo de mapear entidades, atributos e relacionamentos antes de decidir como o banco de dados vai armazená-los.** As entidades são a parte fácil — todo produto conhece seus usuários, pedidos e posts. O ofício está nos *relacionamentos*: quais registros apontam para quais, quantos, e onde essa aresta vive fisicamente. Acerte as arestas e as queries se escrevem sozinhas; erre e cada feature briga com o schema.

## Principais pontos

| Pergunta | Resposta |
| --- | --- |
| Os três níveis | Conceitual (o quê) → lógico (estrutura) → físico (motor) |
| As três arestas | Um-para-um · um-para-muitos · muitos-para-muitos |
| Ferramentas relacionais | Chaves estrangeiras; tabelas de junção para muitos-para-muitos |
| Ferramentas de documentos | Embutir, Pointers (referências), Relations/arrays de IDs |
| A regra moderna | Modele pelos padrões de acesso — dados lidos juntos vivem juntos |

## Os mesmos relacionamentos, nos dois mundos

Relacional primeiro — a chave estrangeira carrega o um-para-muitos, e o muitos-para-muitos precisa se decompor por uma junção:

```sql
-- 1:N — a chave estrangeira vive no lado "muitos"
CREATE TABLE books (
  id        bigint PRIMARY KEY,
  title     text   NOT NULL,
  author_id bigint NOT NULL REFERENCES authors(id) ON DELETE CASCADE
);

-- M:N — nenhuma FK sozinha expressa isso; a tabela de junção guarda as duas chaves
CREATE TABLE book_genres (
  book_id  bigint REFERENCES books(id),
  genre_id bigint REFERENCES genres(id),
  added_at timestamptz DEFAULT now(),     -- junções podem carregar atributos
  PRIMARY KEY (book_id, genre_id)         -- chave composta: uma aresta, uma vez
);
```

Mundo dos documentos, mesmo modelo: a aresta um-para-muitos é um **Pointer** tipado, a muitos-para-muitos é uma **Relation** — nenhuma tabela de junção para inventar, e a aresta é declarada no código da aplicação:

**JavaScript:**

```javascript
// JavaScript / Node.js — Back4app JS SDK
// One-to-many: a Pointer. Many-to-many: a Relation.
const author = await new Parse.Query('Author').get(authorId);

const book = new Parse.Object('Book');
book.set('title', 'Dune');
book.set('author', author);              // Pointer — typed one-to-many edge
await book.save();

const genres = book.relation('genres');  // Relation — many-to-many, unbounded
genres.add([sciFi, classics]);
await book.save();
```

**Flutter:**

```dart
// Flutter / Dart — Back4app Flutter SDK
// One-to-many: a Pointer. Many-to-many: a Relation.
final book = ParseObject('Book')
  ..set('title', 'Dune')
  ..set('author', author.toPointer()); // Pointer — typed one-to-many edge
await book.save();

book.addRelation('genres', [sciFi, classics]); // Relation — many-to-many
await book.save();
```

**Swift:**

```swift
// iOS / Swift — Back4app Swift SDK
// One-to-many: a Pointer. Many-to-many: a Relation.
var book = Book()
book.title = "Dune"
book.author = try author.toPointer()   // Pointer — typed one-to-many edge
let saved = try await book.save()

let relation = try saved.relation("genres")
try await relation.add([sciFi, classics]).save() // Relation — many-to-many
```

**Kotlin:**

```kotlin
// Android / Kotlin — Back4app Android SDK
// One-to-many: a Pointer. Many-to-many: a Relation.
val book = ParseObject("Book").apply {
  put("title", "Dune")
  put("author", author)                 // Pointer — typed one-to-many edge
}
book.save()

val genres = book.getRelation<ParseObject>("genres") // Relation — many-to-many
genres.add(sciFi)
genres.add(classics)
book.save()
```

## Conceitual vs. lógico vs. físico: os três níveis

```mermaid
flowchart LR
  accTitle: Modelos de dados conceitual, lógico e físico
  accDescr: O modelo conceitual nomeia entidades e relacionamentos para a discussão de negócio; o modelo lógico adiciona atributos, tipos e chaves sem depender de tecnologia; o modelo físico se compromete com tabelas ou coleções, índices e constraints num motor de banco de dados específico.
  C["Conceitual<br/>Autor —escreve→ Livro<br/>(o que existe, para humanos)"]
  L["Lógico<br/>+ atributos, tipos, chaves<br/>(estrutura, sem motor definido)"]
  P["Físico<br/>tabelas/coleções, índices,<br/>constraints num motor"]
  C --> L --> P
```

| Dimensão | Conceitual | Lógico | Físico |
| --- | --- | --- | --- |
| Pergunta respondida | O que existe, como se relaciona | Quais campos, quais chaves | Como armazena, quão rápido |
| Público | Todo mundo | Designers do modelo | Engenheiros + o motor |
| Contém | Entidades, relacionamentos | + atributos, tipos, cardinalidade | + índices, constraints, partições |
| Muda quando | O negócio muda | Os requisitos se refinam | O motor ou a escala mudam |

A disciplina que os níveis impõem: não discuta índices enquanto o time ainda discorda sobre o que é um "pedido".

## Todo relacionamento, toda implementação

A tabela que a SERP nunca montou — cada tipo de aresta com sua implementação nos dois mundos:

| Relacionamento | Exemplo | Implementação relacional | Implementação em documentos |
| --- | --- | --- | --- |
| Um-para-um | Usuário ↔ perfil | FK com UNIQUE, ou a mesma linha | Embutir — quase sempre |
| Um-para-poucos | Pessoa → endereços | Tabela filha + FK | Array embutido (limitado) |
| Um-para-muitos | Autor → livros | FK no lado "muitos" | **Pointer** no lado "muitos" |
| Um-para-enormes | Dispositivo → eventos | FK + particionamento | Pointer no *filho*; nunca um array |
| Muitos-para-muitos | Livros ↔ gêneros | Tabela de junção, PK composta | **Relation** ou arrays de pointers |
| Autorreferência | Funcionário → gerente | FK para a própria tabela | Pointer para a própria classe |

Notação de cardinalidade, para ler diagramas: o pé-de-galinha desenha uma barra para "um" e um garfo de três pontas para "muitos"; a [tradição ER](https://en.wikipedia.org/wiki/Entity%E2%80%93relationship_model) escreve 1 e N nas linhas; a UML escreve multiplicidades como `1` e `*`. Três dialetos, uma gramática.

## Normalizar, desnormalizar ou embutir?

A modelagem relacional parte da **normalização** — separar os dados para que cada fato viva uma vez só, protegendo as escritas de anomalias. A modelagem analítica e a de documentos a dobram de propósito: a **denormalização** duplica campos quentes de leitura para matar joins, e **embutir** é a prima nativa dos documentos da denormalização. O [checklist embutir-vs-referenciar](https://www.mongodb.com/docs/manual/data-modeling/concepts/embedding-vs-references/) se comprime em três perguntas: lidos juntos? de um dono só? tamanho limitado? Três sins embutem; qualquer não referencia. E, acima de tudo isso, a regra moderna que os guias generalistas pulam: **liste as queries primeiro**. Um modelo está correto quando os padrões de acesso que ele precisa servir saem baratos — as entidades sozinhas não contam isso.

## Casos de uso comuns

- **Projetar um backend novo.** O rito clássico: nomear entidades, desenhar arestas, escolher implementações pela tabela acima — antes da primeira linha de código.
- **O padrão junção-com-atributos.** Matrículas, assinaturas, itens de pedido — quando a *própria aresta* tem dados (data, quantidade, papel), a junção (ou uma classe de aresta com dois pointers) é entidade de primeira classe.
- **Desembaraçar um schema que cresceu.** Sintomas mapeiam para arestas: linhas duplicadas revelam um muitos-para-muitos mal modelado; documentos inchados revelam um embed sem limite.
- **Migrar entre os mundos.** Relacional→documentos significa re-decidir cada FK como embed vs. pointer; a tabela acima é o dicionário de tradução.
- **Alimentar AI e analytics.** Warehouses querem as arestas explícitas e estáveis — a dívida de modelagem aparece no dia em que você tenta exportar.

## Como modelar cada aresta? Matriz de decisão

| Escolha… | Quando… | Cuidado com… |
| --- | --- | --- |
| Embutir | Lidos juntos, um dono, tamanho limitado | Crescimento: o "poucos" de hoje vira os milhares de amanhã |
| Pointer / FK | Ciclo de vida independente, alta cardinalidade | Indexe — todo lookup e include paga |
| Relation / junção | Muitos-para-muitos, ou a aresta carrega dados | Direção da query: saiba de que lado você vai perguntar |
| Duplicar (denormalizar) | Um campo quente de leitura cruzando uma aresta | Fan-out de update — duplicação é dívida com juros |

## Limitações e trade-offs

- **Modelos congelam premissas.** Decisões de cardinalidade ("um usuário tem um endereço") viram schema; baratas no papel, caras depois do lançamento — modele para a cardinalidade de amanhã.
- **Os dois mundos punem a aresta sem índice.** Colunas de FK e campos de pointer são caminhos de join; esquecer os índices deles é o bug silencioso de performance mais comum.
- **Embutir troca integridade por localidade.** Nenhum motor garante que uma cópia embutida continue consistente com a fonte — isso agora é a sua lógica de update.
- **Junções multiplicam joins; Relations os escondem.** Toda leitura muitos-para-muitos atravessa o armazém de arestas — orce o caminho da query, em qualquer um dos mundos.
- **Modelar por padrão de acesso também tem custo.** Otimizar para as queries de hoje pode casar o schema com o produto de hoje; mantenha o modelo conceitual por perto como o terreno neutro da verdade.

## Modelagem de dados no Back4app

O Back4app é uma plataforma open-source de Backend as a Service (BaaS) que combina banco de dados gerenciado, APIs REST e GraphQL geradas automaticamente, autenticação, armazenamento de arquivos e funções serverless com Cloud Code. Seu vocabulário de modelagem é a coluna de documentos das tabelas acima, elevada a primeira classe: **[Pointers](https://docs.parseplatform.org/js/guide/#relational-data)** são arestas um-para-muitos tipadas, **Relations** carregam o muitos-para-muitos sem junção feita à mão, e arrays cobrem o "poucos e limitado". Toda aresta que você declara é atravessável na hora — `include()` percorre pointers em uma requisição, o GraphQL aninha relações em uma query — e o schema segue visível e editável no dashboard, para que o modelo físico nunca saia do campo de visão do time que desenhou o conceitual.
