Как мне реализовать эту схему в MongoDB? - PullRequest
27 голосов
/ 11 января 2011

Я пытаюсь написать скрипт отслеживания, и у меня возникают проблемы с выяснением того, как база данных должна работать.

В MySQL я бы создал таблицу, которая выглядит как

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

Мне нужно иметь возможность:

  • Просматривать информацию по каждому клику, например IP, Referer, OS и т. Д.
  • Посмотрите, как часто клики поступают с X IP, X Referer, X OS
  • Свяжите каждый щелчок с пользователем и кампанией

Если я что-то сделаю в духе

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

, я столкнусьдве проблемы:

  • Создается новый объект кампании для каждого пользователя, что является проблемой, потому что, если мне нужно обновить свою кампанию, мне нужно обновить объект для каждого пользователя
  • Я ожидаю, что массив Clicks будет содержать БОЛЬШОЙ объем данных, я чувствую, что наличие его в составе объекта User сделает очень медленным запрос

Ответы [ 3 ]

87 голосов
/ 13 января 2011

Хорошо, я думаю, вам нужно разбить это на основные "разновидности".

У вас есть два объекта в стиле «сущность»:

  • User
  • Campaign

У вас есть один объект в стиле "сопоставления":

  • UserCampaign

У вас есть один объект "транзакционного" стиля:

  • Click

Шаг 1: сущность

Давайте начнем с простых: User & Campaign. Это действительно два отдельных объекта, и ни один из них не зависит от своего существования. Также между ними нет явной иерархии: пользователи не принадлежат к кампаниям, а кампании не принадлежат пользователям.

Когда у вас есть два таких объекта верхнего уровня, они обычно получают свою собственную коллекцию. Таким образом, вам понадобится коллекция Users и коллекция Camapaigns.

Шаг 2: отображение

UserCampaign в настоящее время используется для представления отображения N-to-M. Теперь, в общем, когда у вас есть отображение N-в-1, вы можете поместить N внутри 1. Однако, с отображением N-в-M, вам обычно приходится «выбирать сторону».

Теоретически вы можете выполнить одно из следующих действий:

  1. Поместите список Campaign ID s внутри каждого User
  2. Поместите список Users ID s внутри каждого Campaign

Лично я бы сделал # 1. Вероятно, у вас гораздо больше пользователей, которые проводят кампании, и вы, вероятно, хотите разместить массив там, где он будет короче.

Шаг 3: транзакционный

Клик - это действительно совершенно другой зверь. В терминах объекта вы можете подумать следующее: Clicks "принадлежат" a User, Clicks "принадлежат" a Campaign. Таким образом, теоретически, вы можете просто хранить клики, являющиеся частью любого из этих объектов. Легко представить, что клики принадлежат под пользователями или кампаниями.

Но если вы действительно копаете глубже, приведенное выше упрощение действительно ошибочно. В вашей системе Clicks действительно являются центральным объектом. На самом деле, вы даже можете сказать, что пользователи и кампании действительно просто «связаны» с кликом.

Посмотрите на вопросы / вопросы, которые вы задаете. Все эти вопросы на самом деле сосредоточены вокруг кликов. Пользователи и кампании не являются центральным объектом в ваших данных, клики.

Кроме того, клики будут самыми многочисленными данными в вашей системе. У вас будет гораздо больше кликов, чем что-либо еще.

Это самая большая проблема при разработке схемы для таких данных. Иногда вам нужно оттолкнуть «родительские» объекты, когда они не самая важная вещь. Представьте себе создание простой системы электронной коммерции. Ясно, что orders будет «принадлежать» users, но orders настолько важен для системы, что станет объектом «верхнего уровня».

Завершение

Возможно, вам понадобятся три коллекции:

  1. Пользователь -> имеет список Campaign._id
  2. Кампания
  3. Клики -> содержит user._id, campaign._id

Это должно удовлетворить все ваши запросы:

Просмотр информации от каждого клика, например IP, Referer, OS и т. Д.

db.clicks.find()

Посмотрите, как часто приходят клики от X IP, X Referer, X OS

db.clicks.group() или запустите Map-Reduce .

Свяжите каждый клик с пользователем и кампанией

db.clicks.find({user_id : blah}) Также можно вставлять идентификаторы кликов как в пользователей, так и в кампании (если это имеет смысл).

Обратите внимание, что если у вас много и много кликов, вам действительно придется анализировать запросы, которые вы выполняете чаще всего. Вы не можете индексировать каждое поле, поэтому вам часто нужно запускать Map-Reduces, чтобы «свернуть» данные для этих запросов.

3 голосов
/ 12 января 2011

Основная проблема, которую я вижу здесь, заключается в том, что вы пытаетесь применить концепции реляционной базы данных к базе данных, ориентированной на документы. Основное различие между ними состоит в том, что вы беспокоитесь не о схеме или структуре в базах данных NOSQL, а о сборе и документах.

Очень важно / необходимо понимать, что во многих реализациях NOSQL, как и в SQL, нет концепций объединения. Это означает, что если вы распространяете свои данные по коллекциям, вы делаете большую работу, чтобы склеить их позже. Также нет никакой другой выгоды от распространения ваших данных по коллекциям, как при нормализации SQL DB. Вам нужно подумать, какие данные являются частью вашего документа и к какой коллекции они применяются, и никогда не беспокоиться о реализации под NOSQL db. Так что для вашей проблемы ответ может быть ... и поддержит все, что вы просили ...

db.trackclicks ==> коллекция
trackclick = { ОС: XP, Пользователь: Джон Доу, Кампания: {title: test, desc: test, link: url}, Реферер: google.com }

2 голосов
/ 12 января 2011
  1. Для mongodb не проблема обновить большое количество документов, если что-то в какой-то компании было изменено.

  2. Есть ли вложенный сбор или нет на самом деле зависит от того, сколько данных в сборе. В вашем случае, если вы знаете, что коллекция «Клики» будет содержать «БОЛЬШОЙ объем данных», вам нужно создать отдельную коллекцию. Потому что для «кликов» вам наверняка понадобятся пейджинг, фильтрация и т. Д., А у пользователя будет «легкая» коллекция.

Итак, я предлагаю следующее:

User {
     Campaigns: []
}

Clicks {
 user_id,
 camp_id
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...