2011-01-11 15 views
26

Estoy tratando de escribir un script de seguimiento y estoy teniendo problemas para averiguar cómo debería funcionar la base de datos.¿Cómo debo implementar este esquema en MongoDB?

En MySQL que crearía una tabla que tiene una apariencia similar a

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 

tengo que ser capaz de:

  • ver la información de cada clic como IP, Referer, sistema operativo, etc.
  • ver cuántas veces los clics provienen de X IP, X Referer, OS X
  • Asociado con cada clic de un usuario y una campaña

Si hago algo en la línea de

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

me topo con dos problemas:

  • Se crea un nuevo objeto de campaña para cada usuario que es un problema porque si tengo que actualizar mi campaña necesitaría actualizar el objeto para cada usuario
  • Espero que la matriz de Clicks contenga una GRAN cantidad de datos, siento que tenerla como parte del objeto Usuario hará que sea muy lento consultar

Respuesta

85

OK, creo que es necesario dividir esto en las "variedades" básicas.

Tiene dos "entidad" al estilo de los objetos:

  • User
  • Campaign

Tienes un "mapeo" al estilo de objeto:

  • UserCampaign

Usted tiene una "transaccional" objeto de estilo:

  • Click

Paso 1: Entidad

Vamos a empezar con las más fáciles: User & Campaign. Estos son realmente dos objetos separados, ninguno de los dos depende realmente del otro para su existencia. Tampoco hay una jerarquía implícita entre los dos: los usuarios no pertenecen a las campañas, ni las campañas pertenecen a los usuarios.

Cuando tiene dos objetos de nivel superior como este, generalmente ganan su propia colección. Por lo tanto, querrá una colección Users y una colección Camapaigns.

Paso 2: cartografía

UserCampaign se utiliza actualmente para representar un mapeo-N-a M. Ahora, en general, cuando tiene una asignación N-a-1, puede poner el N dentro de 1. Sin embargo, con la asignación N-a-M, generalmente debe "elegir un lado".

En teoría, se podría hacer una de las siguientes:

  1. Ponga una lista de Campaign ID s en el interior de cada User
  2. Ponga una lista de Users ID s en el interior de cada Campaign

Personalmente, haría el # 1. Probablemente tenga mucho más usuarios que hagan campañas, y probablemente quiera poner la matriz donde será más corta.

Paso 3: transaccional

clics es realmente una bestia completamente diferente. En términos de objeto, podría pensar lo siguiente: Clicks "pertenecer a" un User, Clicks "pertenecer a" un Campaign. Entonces, en teoría, usted podría simplemente almacenar los clics que son parte de cualquiera de estos objetos. Es fácil pensar que los clics pertenecen al bajo Usuarios o Campañas.

Pero si realmente profundizas más, la simplificación anterior es realmente defectuosa. En su sistema, Clicks son realmente un objeto central. De hecho, es posible que incluso pueda decir que las campañas de los usuarios & están realmente "asociadas con" el clic.

Eche un vistazo a las preguntas/consultas que está haciendo. Todas esas preguntas en realidad se centran en los clics. Usuarios & Las campañas no son el objeto central en sus datos, los clics son.

Además, los clics serán los datos más abundantes en su sistema. Tendrás más clics que cualquier otra cosa.

Este es el problema más grande cuando se diseña un esquema para datos como este. A veces es necesario expulsar objetos "parentales" cuando no son lo más importante. Imagine construir un sistema simple de comercio electrónico. Está claro que orders "pertenece" a users, pero orders es tan central para el sistema que va a ser un objeto de "nivel superior".

envolviéndolo

Usted probablemente querrá tres colecciones:

  1. usuario -> tiene lista de campaign._id
  2. Campaña
  3. Clicks -> contiene user._id , campaign._id

Esto debería satisfacer a todos ustedes ur consulta necesita:

ver la información de cada clic como IP, Referer, sistema operativo, etc

db.clicks.find() 

ver cuántas veces los clics provienen de X IP, X Referer, X OS

db.clicks.group() o ejecuta un Map-Reduce.

asociar cada clic en un usuario y una campaña

db.clicks.find({user_id : blah}) También es posible empujar clic en ID de los usuarios y de las campañas (si eso tiene sentido).

Tenga en cuenta que si tiene muchos clics, realmente tendrá que analizar las consultas que ejecuta más. No puede indexar en todos los campos, por lo que a menudo querrá ejecutar Map-Reduces para "acumular" los datos para estas consultas.

+2

¡Gracias por la gran respuesta! Realmente me ayudó a entender en qué debería pensar al diseñar mis esquemas –

+1

Esta es una gran explicación. Deberías moverlo a un blog :). Dicho esto, ¿qué tan bien funcionará esto en MongoDB si necesita leer los datos cada pocos segundos con los hallazgos anteriores? ¿Mongo es la mejor solución en tal situación o alguna otra base de datos lo manejará mejor? – retrobrain

+0

Depende, ¿está leyendo las tres colecciones o solo * algunas * de las colecciones?¿Qué consultas estás realizando? –

2
  1. No es problema para mongodb actualizar una gran cantidad de documentos si algo en alguna compañía ha sido cambiado.

  2. Tener colección anidada o no realmente depende de la cantidad de datos en la colección. En su caso, si sabe que la colección 'Clics' contendrá 'GRAN cantidad de datos', necesita crear una colección separada. Porque seguro para los 'Clics' necesitarás paginación, filtrado y etc. y el usuario será una colección 'ligera'.

por lo que sugiero lo siguiente:

User { 
    Campaigns: [] 
} 

Clicks { 
user_id, 
camp_id 
} 
3

El principal problema que veo aquí es que usted está tratando de aplicar los conceptos bases de datos relacionales en una base de datos documental. La principal diferencia entre los dos es que no se preocupe por el esquema o la estructura en las bases de datos NOSQL, sino más bien por la recopilación y los documentos.

Es muy importante/imperativo entender que no hay conceptos de unión en muchas implementaciones de NOSQL como en SQL. Esto significa que si distribuyes tus datos entre las colecciones, entonces trabajas mucho para pegarlas más tarde. Además, no hay otra ganancia al distribuir sus datos entre colecciones como en las normalizaciones de SQL db. Debe pensar qué datos son parte de su documento y a qué colección se aplica y no preocuparse por las implementaciones debajo de NOSQL db. Así que para su problema de la respuesta podría be..and apoyará todo lo que pediste ...

db.trackclicks ==> Colección
trackclick = { OS: XP, usuario: John Doe, de campaña: {title: test, desc: test, link: url}, Recomendado: google.com }

Cuestiones relacionadas