Como devo implementar esse esquema no MongoDB?

Estou tentando escrever um script de acompanhamento e estou tendo problemas para descobrir como o database deve funcionar.

No MySQL eu criaria uma tabela parecida com

User: username_name: string Campaign: title: string description: string link: string UserCampaign: user_id: integer camp_id: integer Click: os: text referer: text camp_id: integer user_id: integer 

Eu preciso ser capaz de:

  • Veja as informações de cada clique como IP, Referer, OS, etc
  • Veja quantos cliques são provenientes de X IP, X Referer, X OS
  • Associe cada clique a um usuário e a uma campanha

Se eu fizer algo ao longo das linhas de

 User { Campaigns: [ { Clicks: [] } ] } 

Eu me deparo com dois problemas:

  • Ele cria um novo object de campanha para cada usuário, o que é um problema, pois se eu precisar atualizar minha campanha, precisarei atualizar o object para cada usuário
  • Espero que a matriz de Cliques contenha uma grande quantidade de dados, sinto que ter uma parte do object Usuário tornará muito lento a consulta

OK, acho que você precisa dividir isso nas “variedades” básicas.

Você tem dois objects de estilo “entidade”:

  • User
  • Campaign

Você tem um object de estilo “mapeamento”:

  • UserCampaign

Você tem um object de estilo “transacional”:

  • Click

Etapa 1: entidade

Vamos começar com os fáceis: User & Campaign . Estes são verdadeiramente dois objects separados, nenhum deles realmente depende do outro para sua existência. Também não há hierarquia implícita entre os dois: os usuários não pertencem a Campanhas, nem as Campanhas pertencem a Usuários.

Quando você tem dois objects de nível superior como esse, eles geralmente ganham sua própria coleção. Então você vai querer uma coleção de Users e uma coleção Camapaigns .

Etapa 2: mapeamento

UserCampaign é usada atualmente para representar um mapeamento de N para M. Agora, em geral, quando você tem um mapeamento N-para-1, você pode colocar o N dentro do 1. No entanto, com o mapeamento N-to-M, você geralmente precisa “escolher um lado”.

Em teoria, você poderia fazer o seguinte:

  1. Coloque uma lista de Campaign ID de Campaign ID dentro de cada User
  2. Coloque uma lista de Users ID de Users ID dentro de cada Campaign

Pessoalmente, eu faria # 1. Você provavelmente tem muito mais usuários do que campanhas e provavelmente desejará colocar a matriz onde ela será mais curta.

Etapa 3: transacional

Cliques é realmente uma besta completamente diferente. Em termos de object, você poderia pensar o seguinte: os Clicks “pertencem a” um User , os Clicks “pertencem a” uma Campaign . Então, em teoria, você poderia simplesmente armazenar cliques como parte de qualquer um desses objects. É fácil pensar que os Cliques pertencem a Usuários ou Campanhas.

Mas se você realmente cavar mais fundo, a simplificação acima é realmente falha. No seu sistema, os Clicks são realmente um object central. Na verdade, você pode até dizer que os Usuários e Campanhas estão realmente “associados” ao clique.

Dê uma olhada nas perguntas / consultas que você está fazendo. Todas essas perguntas estão cinputs em cliques. Usuários e campanhas não são o object central em seus dados, os cliques são.

Além disso, os Cliques serão os dados mais abundantes em seu sistema. Você terá muito mais cliques do que qualquer outra coisa.

Este é o maior obstáculo ao projetar um esquema para dados como este. Às vezes você precisa empurrar objects “parent” quando eles não são a coisa mais importante. Imagine criar um sistema simples de comércio eletrônico. É claro que os orders “pertenceriam” users , mas os orders são tão importantes para o sistema que serão um object de “nível superior”.

Embrulhando-o

Você provavelmente vai querer três collections:

  1. Usuário -> tem lista de campaign._id
  2. Campanha
  3. Cliques -> contém user._id, campaign._id

Isso deve satisfazer todas as suas necessidades de consulta:

Veja as informações de cada clique como IP, Referer, OS, etc

 db.clicks.find() 

Veja quantos cliques são provenientes de X IP, X Referer, X OS

db.clicks.group() ou execute um Map-Reduce .

Associe cada clique a um usuário e a uma campanha

db.clicks.find({user_id : blah}) Também é possível enviar IDs de cliques para usuários e campanhas (se isso fizer sentido).

Tenha em atenção que, se tiver muitos e muitos cliques, terá de analisar as consultas mais executadas. Você não pode indexar em todos os campos, portanto, muitas vezes, você deseja executar o Map-Reduces para “acumular” os dados dessas consultas.

O principal problema que vejo aqui é que você está tentando aplicar os conceitos de database relacional em um database orientado a documentos. A principal diferença entre os dois é que você não se preocupa com o esquema ou a estrutura nos bancos de dados do NOSQL, mas sim com a coleta e os documentos.

É muito importante / imperativo entender que não há conceitos de junit em muitas implementações do NOSQL como no SQL. Isso significa que, se você distribuir seus dados pelas collections, fará muito trabalho para colá-los mais tarde. Também não há nenhum outro ganho, espalhando seus dados através de collections, como nas normalizações do database SQL. Você precisa pensar quais dados fazem parte do seu documento e em qual coleção ele se aplica e nunca se preocupar com implementações sob o database do NOSQL. Então, para o seu problema, a resposta poderia ser … e apoiar tudo o que você pediu …

db.trackclicks ==> coleção
trackclick = {OS: XP, Usuário: John Doe, Campanha: {title: test, desc: teste, link: url}, Indicador: google.com}

  1. Não é problema para o mongodb atualizar grande quantidade de documentos se alguma coisa de alguma empresa foi alterada.

  2. A coleção aninhada ou não depende realmente da quantidade de dados na coleção. No seu caso, se você souber que a coleção “Cliques” conterá “GRANDE quantidade de dados”, será necessário criar uma coleção separada. Porque com certeza para os “Cliques” você precisará de paginação, filtragem e etc. e que o usuário será uma coleção “leve”.

Então eu sugiro seguir:

 User { Campaigns: [] } Clicks { user_id, camp_id }