Вопрос или проблема
Я хочу запросить взаимные совпадения пользователя для всех событий, в которых он когда-либо участвовал.
Я использую 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;
}
Объяснение кода
- Запрос событий: Мы получаем события, которые пользователь посетил, через
usersToEvents
. - Поиск взаимных матчей: Используем
innerJoin
наeventUserUserRatings
, чтобы найти все лайки, связанные с тем же событием, для обоих пользователей. - Форматирование выходных данных: Мы группируем результаты взаимных матчей по идентификатору события и затем объединяем их с событиями, чтобы обеспечить детализированный результат.
Шаг 3: Тестирование и отладка
Необходимо протестировать данный запрос в тестовой среде, чтобы убедиться в его правильности:
- Проверьте на нескольких событиях с разными пользователями.
- Убедитесь, что результаты корректно отображают взаимные лайки.
Заключение
Таким образом, приведенный выше код должен успешно находить взаимные лайки между пользователями на основе событий, которые они посещали. Каждый шаг в коде ориентирован на получение и обработку данных для достижения необходимого результата. Применение дополнительных проверок при отладке упростит дальнейший процесс получения данных и улучшит общую стабильность приложения.