Ответ
Да, активно использовал Foreign Key (внешние ключи) в реляционных базах данных для обеспечения ссылочной целостности. В Node.js проектах это реализуется либо на уровне схемы БД (например, в PostgreSQL), либо через ORM.
Пример с Sequelize (PostgreSQL):
// Определение моделей со связью
const User = sequelize.define('User', {
id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true },
name: DataTypes.STRING
});
const Post = sequelize.define('Post', {
id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true },
title: DataTypes.STRING,
userId: {
type: DataTypes.INTEGER,
references: {
model: User,
key: 'id'
},
onDelete: 'CASCADE', // Автоматическое удаление зависимых записей
onUpdate: 'CASCADE'
}
});
// Определение ассоциации
Post.belongsTo(User, { foreignKey: 'userId' });
User.hasMany(Post, { foreignKey: 'userId' });
Практические преимущества, которые я наблюдал:
- Целостность данных: Невозможно создать пост с несуществующим
userId - Каскадные операции: При удалении пользователя автоматически удаляются все его посты (при
onDelete: 'CASCADE') - Упрощение запросов: Sequelize автоматически строит JOIN-запросы при использовании
include
Пример запроса с JOIN через ассоциацию:
const postsWithUsers = await Post.findAll({
include: [{
model: User,
attributes: ['name', 'email']
}]
});
В проектах с MongoDB использовал аналогичные концепции через ref в схемах Mongoose, хотя там нет настоящих внешних ключей на уровне базы.
Ответ 18+ 🔞
Э, слушай, а вот про внешние ключи — это вообще отдельная песня, ебушки-воробушки. Я их, конечно, юзал в реляционных базах, чтобы эта самая ссылочная целостность была, а то без неё — пизда рулю, честно говоря. В ноде это либо на уровне самой базы настраивается, либо через ORM типа Sequelize.
Вот смотри, как в Sequelize под PostgreSQL это выглядит:
// Модели объявляем со связью
const User = sequelize.define('User', {
id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true },
name: DataTypes.STRING
});
const Post = sequelize.define('Post', {
id: { type: DataTypes.INTEGER, primaryKey: true, autoIncrement: true },
title: DataTypes.STRING,
userId: {
type: DataTypes.INTEGER,
references: {
model: User,
key: 'id'
},
onDelete: 'CASCADE', // Это чтобы всё каскадом почистилось
onUpdate: 'CASCADE'
}
});
// А вот и ассоциации
Post.belongsTo(User, { foreignKey: 'userId' });
User.hasMany(Post, { foreignKey: 'userId' });
И польза от этого, надо сказать, овердохуища:
- Данные не разъебутся: Не получится воткнуть в пост
userIdот левого мужика с улицы — база не пропустит, ёпта. - Каскад — это сила: Удалил юзера — и все его посты автоматом накрылись медным тазом, если
onDelete: 'CASCADE'стоит. Красота, а не жизнь. - Запросы проще: Sequelize сам эти JOIN'ы тебе нарисует, когда через
includeпопросишь.
Вот, например, как пост с юзером одним запросом вытащить:
const postsWithUsers = await Post.findAll({
include: [{
model: User,
attributes: ['name', 'email']
}]
});
А в MongoDB, хоть там и нет настоящих внешних ключей как в SQL, я в схемах Mongoose через ref ту же идею реализовывал. В общем, штука полезная, без неё — доверия ебать ноль к данным.