Как сделать запрос с помощью drizzle-kit, если два пользователя нравятся друг другу

Вопрос или проблема

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

Я использую drizzle-kit SQLite Turso и next.js, у меня есть запрос, который возвращает понравившихся пользователей, но не взаимные совпадения.

Я попробовал все, но это просто не работает.
Думаю, нам нужно еще одно внутреннее соединение, чтобы снова присоединить usersToEvents.
Я также пробовал
const r1 = aliasedTable(...)
const r2 = aliasedTable(....)

Думаю, const matches = ... работает неправильно.

export async function getUserEventsWithMatches(
  userId: string,
  locale: LocaleType
): Promise<EventWithMatches[]> {
  const attendedEvents = await db
    .select({
      eventId: events.id,
      title: eventTranslations.title,
      date: events.date,
      matchesRevealed: events.matchesRevealed,
      location: {
        id: locations.id,
        postalCode: locations.postalCode,
        city: locations.city,
        address: locations.address,
        houseNumber: locations.houseNumber,
        name: locations.name,
      },
    })
    .from(events)
    .innerJoin(usersToEvents, eq(events.id, usersToEvents.eventId))
    .leftJoin(locations, eq(locations.id, events.locationId))
    .leftJoin(
      eventTranslations,
      and(
        eq(eventTranslations.eventType, events.eventType),
        eq(eventTranslations.locale, locale)
      )
    )
    .where(eq(usersToEvents.userId, userId))
    .groupBy(events.id)
    .orderBy(desc(events.date))
    .all();

  const matches = await db
    .select({
      eventId: eventUserUserRatings.eventId,
      userId: users.id,
      nickname: users.nickname,
      instagram: users.instagram,
      facebook: users.facebook,
      email: users.email,
    })
    .from(eventUserUserRatings)
    .innerJoin(users, eq(eventUserUserRatings.ratedUserId, users.id))
    .where(
      and(
        eq(eventUserUserRatings.raterUserId, userId),
        eq(eventUserUserRatings.isLiked, true)
      )
    )
    .all();

  const eventMatchesMap: Record<string, MatchingUser[]> = matches.reduce(
    (acc: Record<string, MatchingUser[]>, match: MatchingUser) => {
      const { eventId, ...userMatch } = match;
      if (!acc[eventId]) {
        acc[eventId] = [];
      }
      acc[eventId].push({ eventId, ...userMatch });
      return acc;
    },
    {}
  );

  const result: EventWithMatches[] = attendedEvents.map(
    (event: AttendedEvent) => ({
      ...event,
      matches: eventMatchesMap[event.eventId] || [],
    })
  );

  return result;
}

Связь:

import { relations } from "drizzle-orm";
import {
  integer,
  primaryKey,
  sqliteTable,
  text,
} from "drizzle-orm/sqlite-core";

import { events } from "./events";
import { users } from "./users";

export const eventUserUserRatings = sqliteTable(
  "event_user_user_ratings",
  {
    eventId: text("event_id")
      .notNull()
      .references(() => events.id),
    raterUserId: text("rater_user_id")
      .notNull()
      .references(() => users.id),
    ratedUserId: text("rated_user_id")
      .notNull()
      .references(() => users.id),
    isLiked: integer("is_liked", { mode: "boolean" }).notNull(),
  },
  (t) => ({
    pk: primaryKey({ columns: [t.eventId, t.raterUserId, t.ratedUserId] }),
  })
);

export const eventUserUserRatingsRelations = relations(
  eventUserUserRatings,
  ({ one }) => ({
    event: one(events, {
      fields: [eventUserUserRatings.eventId],
      references: [events.id],
    }),
    raterUser: one(users, {
      fields: [eventUserUserRatings.raterUserId],
      references: [users.id],
    }),
    ratedUser: one(users, {
      fields: [eventUserUserRatings.ratedUserId],
      references: [users.id],
    }),
  })
);

Ответ или решение

Как выполнить запрос в drizzle-kit для нахождения взаимных лайков пользователей

Данная инструкция направлена на решение задачи по запросу взаимных лайков между пользователями в системе, использующей базу данных SQLite и библиотеку drizzle-kit. Мы рассмотрим подход к оптимизации вашего текущего кода, чтобы добиться нужного результата.

Шаг 1: Понимание структуры данных

Вы используете таблицу eventUserUserRatings, которая связывает события с пользователями через лайки. Основные поля:

  • eventId: идентификатор события.
  • raterUserId: идентификатор пользователя, который поставил лайк.
  • ratedUserId: идентификатор пользователя, которому поставлен лайк.
  • isLiked: статус лайка пользователя (TRUE или FALSE).

Таким образом, для определения взаимных лайков между двумя пользователями, необходимо проверить, есть ли запись о том, что пользователь A лайкнул пользователя B, и наоборот.

Шаг 2: Обновление запроса для нахождения взаимных лайков

В вашем текущем запросе мы можем оптимизировать логику для нахождения взаимных лайков, добавив вложенные запросы и дополнительные соединения. Вот пример обновленного кода:

export async function getUserEventsWithMutualMatches(
  userId: string,
  locale: LocaleType
): Promise<EventWithMatches[]> {
  // Получение всех посещенных событий текущим пользователем
  const attendedEvents = await db
    .select({
      eventId: events.id,
      title: eventTranslations.title,
      date: events.date,
      matchesRevealed: events.matchesRevealed,
      location: {
        id: locations.id,
        postalCode: locations.postalCode,
        city: locations.city,
        address: locations.address,
        houseNumber: locations.houseNumber,
        name: locations.name,
      },
    })
    .from(events)
    .innerJoin(usersToEvents, eq(events.id, usersToEvents.eventId))
    .leftJoin(locations, eq(locations.id, events.locationId))
    .leftJoin(
      eventTranslations,
      and(
        eq(eventTranslations.eventType, events.eventType),
        eq(eventTranslations.locale, locale)
      )
    )
    .where(eq(usersToEvents.userId, userId))
    .groupBy(events.id)
    .orderBy(desc(events.date))
    .all();

  // Получение всех взаимных матчей
  const mutualMatches = await db
    .select({
      eventId: eventUserUserRatings.eventId,
      matchedUserId: eventUserUserRatings.ratedUserId,
      nickname: users.nickname,
      instagram: users.instagram,
      facebook: users.facebook,
      email: users.email,
    })
    .from(eventUserUserRatings)
    .innerJoin(users, eq(eventUserUserRatings.ratedUserId, users.id))
    .where(
      and(
        eq(eventUserUserRatings.isLiked, true),
        eq(eventUserUserRatings.eventId, eventUserUserRatings.eventId)
      )
    )
    .innerJoin(
      eventUserUserRatings as eventRatingsSelf,
      and(
        eq(eventUserUserRatings.eventId, eventRatingsSelf.eventId),
        eq(eventRatingsSelf.ratedUserId, userId),
        eq(eventRatingsSelf.isLiked, true)
      )
    )
    .all();

  // Формирование мапы для взаимных матчей
  const eventMatchesMap: Record<string, MatchingUser[]> = mutualMatches.reduce(
    (acc: Record<string, MatchingUser[]>, match: MatchingUser) => {
      const { eventId, ...userMatch } = match;
      if (!acc[eventId]) {
        acc[eventId] = [];
      }
      acc[eventId].push({ eventId, ...userMatch });
      return acc;
    },
    {}
  );

  // Итоговая структура данных
  const result: EventWithMatches[] = attendedEvents.map(
    (event: AttendedEvent) => ({
      ...event,
      matches: eventMatchesMap[event.eventId] || [],
    })
  );

  return result;
}

Объяснение кода

  1. Запрос событий: Мы получаем события, которые пользователь посетил, через usersToEvents.
  2. Поиск взаимных матчей: Используем innerJoin на eventUserUserRatings, чтобы найти все лайки, связанные с тем же событием, для обоих пользователей.
  3. Форматирование выходных данных: Мы группируем результаты взаимных матчей по идентификатору события и затем объединяем их с событиями, чтобы обеспечить детализированный результат.

Шаг 3: Тестирование и отладка

Необходимо протестировать данный запрос в тестовой среде, чтобы убедиться в его правильности:

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

Заключение

Таким образом, приведенный выше код должен успешно находить взаимные лайки между пользователями на основе событий, которые они посещали. Каждый шаг в коде ориентирован на получение и обработку данных для достижения необходимого результата. Применение дополнительных проверок при отладке упростит дальнейший процесс получения данных и улучшит общую стабильность приложения.

Оцените материал
Добавить комментарий

Капча загружается...