1

Тема: Складний запит з декількох колекцій в MongoDB

Вітаю.
Маю таку ось діаграму

Прихований текст

https://replace.org.ua/uploads/images/2564/03a86cc4fba4ae6e2836b2fa226b616d.png

У нас є багато різних компаній. Кожна компанія може мати кільканадцять рекламщиків (Advertiser) асоційованих з нею. Кожен рекламщик, в свою чергу, може мати кільканадцять брендів асоційованих з цим рекламщиком. Бренди ж можуть мати багацько рекламних кампаній (Campaign), а ці рекламні кампанії можуть мати різну кількість стратегій (Strategy).

Мені треба витягнути інфу про кампанії (Campaign), котрі стосуються певної компанії (Company), але також мені треба витягнути ім'я рекламщика та бренду, котрі асоціюються з певною кампанією, а ще треба показати "статус" компанії, котрий обраховується беручи до уваги статуси всіх стратегій, котрі стосуються цієї кампанії (Campaign).

Тобто, кінцевий результат має виглядати якось тако:
на вхід отримуємо id компанії (Company), а на вихід табличку з такими полями
Campaign name, Advertiser name, Brand name, Campaign status.
********************************

Маю кілька ідею, але вона якась складна та заплутана...

Якщо нам треба саме кампанії, то перший запит повинен бути саме до кампаній, але кампанії не мають на собі id компанії, котрої стосуються, тому нам треба проходитись по кожній кампанії, далі шукати бренд, в межах котрого вона була запущена, і потім брати company_id з цього бренду, і перевіряти, чи він рівний тому company_id, який ми отримали на вхід, ну і далі вже відштовхуватись від об'єкту бренду, бо він пов'язує кампанію, компанію, рекламщика та стратегії.

Але запит буде ой який складний (а може ні?), і я ще ніяк не можу розібратись, як його скласти...
********************************

Ще ідея є - поки застосунок ще в розробці, то може краще чіпляти тим кампаніям (Campaign) company_id, аби потім швидко знайти лише ті кампанії, котрі нас цікавлять. І так, як рекламщики та бренди мають на собі company_id, то розібратись з ними буде легко.

Шо думаєте?

2 Востаннє редагувалося koala (09.11.2021 18:47:31)

Re: Складний запит з декількох колекцій в MongoDB

Рекламник може працювати лише з однією компанією? Якщо так, то бренд не має посилатися на компанію, а лише на рекламника, який із ним працює, інакше це дублювання. Або навпаки, рекламник має посилатися на бренд, а не на компанію, N:N (ще одна табличка). Що станеться, якщо Бренд каже "рекламник Вася, Кока-Кола", а у Васі написано, що він працює з Пепсі?
Те саме з кампаніями. Нащо там посилання на бренд? Є стратегія, що посилається на бренд і кампанію - значить, ця кампанія відноситься до цього бренда.
Ну а так - звичайний JOIN.

SELECT Campaign name, Advertiser name, Brand name, Campaign status
FROM Company INNER JOIN Brand ON Brand.Company_id == Company._id
             INNER JOIN Strategy ON Strategy.Brand_id = Brand._id
             INNER JOIN Campaign ON Campaign.Brand_id = Brand._id 'або ON Strategy.Campaign_id = Campaign._id
WHERE Company._id = ....
Подякували: FakiNyan1

3

Re: Складний запит з декількох колекцій в MongoDB

так монгодб це nosql же ж, sql тут не робе. Це так робили папєрєднікі, а якби я сам робив, то хз, чи воно було б краще, чи ще гірше.
Поки зробив так, і ніби робе

Прихований текст
const campaigns = await Campaign.aggregate([
    {
      $lookup: { // це шось штибу join'а. Воно проходе по кожній Campaign, бере brand_id, і шукає об'єкт brand в табличці brands з таким самим id
        from: 'brands',
        localField: 'brand_id',
        foreignField: '_id',
        as: 'brand',
      },
    },
    {
      $unwind: { // тут ми ніби беремо масив brand (це буде масив лише з 1 об'єктом) і розгортає його в купку об'єктів, кожен об'єкт має унікальний brand
        path: '$brand',
      },
    },
    {
      $match: { // тут воно фільтрує всі попередні об'єкти, щоб залишались лише ті, де brand.company_id == company_id 
        'brand.company_id': mongoose.Types.ObjectId(company_id),
      },
    },
    {
      $lookup: { // тут воно знаходить стратегії, що асоціюються з даною кампанією
        from: 'strategies',
        localField: '_id',
        foreignField: 'campaign_id',
        as: 'strategies',
      },
    },
    {
      $lookup: { // тут те саме, але шукає рекламника бренду (це масив з 1 об'єктом)
        from: 'advertisers',
        localField: 'brand.advertiser_id',
        foreignField: '_id',
        as: 'advertiser',
      },
    },
    {
      $unwind: { // тут ми витягуємо рекламника з масиву, щоб воно було на самому об'єкті, а не в масиві, що на об'єкті
        path: '$advertiser',
      },
    },
    {
      $set: { // ну а це я вже тупо перейменовую то всьо, шоб гарно і зрозуміло було. Після цього ще йде $project, котрий залишає лише потрібні поля, але то вже таке.
        brand_name: '$brand.name',
        campaign_name: '$name',
        advertiser_name: '$advertiser.name',
      },
    }];

4 Востаннє редагувалося mykhas (15.12.2021 16:04:21)

Re: Складний запит з декількох колекцій в MongoDB

Взагалі тут має працювати https://docs.mongodb.com/manual/aggregation/ зі не дуже складним запитом. План має бути десь такий:
1. вибірка компаній за критерієм;
2. $lookup на advertiser;
3. $unnest нового поля advertiser. Тепер, якщо ви маєте 2 компанії з трьома "дорадниками" в кожної, у вас має бути 6 об'єктів в результаті;
4. повторювати кроки 2 і 3, поки не приєднаєте всі потрібні моделі;
5. трансформувати вивід з $project.

Все це писати й дебажити простіше з MongoDB Compass, наприклад; для колекції там є можливість явної агрегації і перегляду результату після кроку. А можна й просто писати й виконувати JSON в будь-якій мові.

Подякували: FakiNyan, leofun012

5

Re: Складний запит з декількох колекцій в MongoDB

mykhas написав:

Взагалі тут має працювати https://docs.mongodb.com/manual/aggregation/ зі не дуже складним запитом. План має бути десь такий:
1. вибірка компаній за критерієм;
2. $lookup на advertiser;
3. $unnest нового поля advertiser. Тепер, якщо ви маєте 2 компанії з трьома "дорадниками" в кожної, у вас має бути 6 об'єктів в результаті;
4. повторювати кроки 2 і 3, поки не приєднаєте всі потрібні моделі;
5. трансформувати вивід з $project.

Все це писати й дебажити простіше з MongoDB Compass, наприклад; для колекції там є можливість явної агрегації і перегляду результату після кроку. А можна й просто писати й виконувати JSON в будь-якій мові.

агрегація в компасі - це просто якесь щастя, дякую, шо розповіли про то, бо я шось геть його не помічав

6

Re: Складний запит з декількох колекцій в MongoDB

Здається ви не правильно МонгоДБ використовуєте, не для тих цілей.

Подякували: leofun011

7

Re: Складний запит з декількох колекцій в MongoDB

Vo_Vik написав:

Здається ви не правильно МонгоДБ використовуєте, не для тих цілей.

коли здається, хреститись тре

8

Re: Складний запит з декількох колекцій в MongoDB

Faki, як думаєте чому бази даних ділять на реляційні і ні? І що означає те слово реляційні. І до якого типу відноситься Монго?

Подякували: leofun011

9

Re: Складний запит з декількох колекцій в MongoDB

Vo_Vik написав:

Faki, як думаєте чому бази даних ділять на реляційні і ні? І що означає те слово реляційні. І до якого типу відноситься Монго?

бо є реляційні, а є нереляційні
то значе, що там всьо побудовано на зв'язках між таблицями
монго до нереляційних, але там є інструменти для роблення деяких речей, котрі притаманні реляційним бд

Подякували: bvn1

10

Re: Складний запит з декількох колекцій в MongoDB

Ну, а я що говорю? Ви використовуєте Монго для не притаманних для неї речей. Може варто задуматись про зміну архітектури.

11

Re: Складний запит з декількох колекцій в MongoDB

Vo_Vik написав:

Ну, а я що говорю? Ви використовуєте Монго для не притаманних для неї речей. Може варто задуматись про зміну архітектури.

Ви якийсь дивний, я ж писав вже, що на цьому проєкті працювали до мене. Я не буду переписувати все з нуля, бо Во_Вік на реплейсі так сказав, а клієнт не буде платити за це гроші і чекати, поки весь бекенд перепишеться на щось інше.

Подякували: Q-bart1

12

Re: Складний запит з декількох колекцій в MongoDB

Насправді це класна тема для розмови.

Взагалі про різницю між SQL і no-SQL базами даних гарно пише Клеппманн в своїй Designing Data-Intensive Applications, дуже раджу почитати розділ 2 звідти.

Якщо дуже коротко, то в цьому контексті різниця власне в ефективності JOIN'у/$lookup. Так, в Mongo (теоретично) буде повільніше, за умови що foreign keys/indexes правильно налаштовані в обох базах. Водночас, у Mongo є й чимало переваг: в першу чергу швидкість створення документів, кращі можливості для sharding'у, відсутність визначених структур даних. Для більшості проектів, з огляду на не надто суттєву різницю в перфомансі і (часто) не найстрогіші вимоги до швидкодії, підійдуть обидва варіанти. Переписувати все на реляційну базу просто замість того щоб використовувати $lookup звісно не варто, але з часом потреба в цьому і справді може з'явитися; важливо, щоб вона була трохи вагомішою, ніж неочевидний JSON-синтакс

Подякували: FakiNyan1