Введение: Базы данных в экосистеме Swift
Swift давно вышел за рамки простой разработки мобильных приложений. С появлением серверных фреймворков, таких как Vapor и Perfect, язык стал полноценным инструментом для создания бэкендов. Однако работа с базами данных на Swift имеет свою специфику. В отличие от Python или JavaScript, здесь нет встроенных драйверов — всё решается через сторонние пакеты.
В этой статье мы разберём, как подключаться к двум популярным СУБД: реляционной PostgreSQL и документо-ориентированной MongoDB. Вы узнаете, какие библиотеки использовать, как настроить подключение и выполнять базовые CRUD-операции. Примеры ориентированы на iOS/macOS, но код будет работать и в серверном окружении.
PostgreSQL в Swift: классика через Vapor и Fluent
Выбор библиотеки
Для работы с PostgreSQL в Swift стандартом де-факто является Fluent — ORM от фреймворка Vapor. Fluent поддерживает PostgreSQL, MySQL, SQLite и MongoDB (через отдельный драйвер). Если вам нужна работа без Vapor, используйте PostgresClientKit — низкоуровневый драйвер.
Настройка подключения
Добавьте зависимость в Package.swift:
.package(url: "https://github.com/vapor/fluent-postgres-driver.git", from: "2.0.0")
Базовая конфигурация в configure.swift:
import Fluent
import FluentPostgresDriver
import Vapor
public func configure(_ app: Application) throws {
app.databases.use(.postgres(
hostname: "localhost",
port: 5432,
username: "swift_user",
password: "secret",
database: "swift_db"
), as: .psql)
// Добавляем миграции
app.migrations.add(CreateUser())
}
CRUD-операции на примере модели User
Создадим модель и миграцию:
final class User: Model, Content {
static let schema = "users"
@ID(key: .id)
var id: UUID?
@Field(key: "name")
var name: String
@Field(key: "email")
var email: String
init() { }
init(id: UUID? = nil, name: String, email: String) {
self.id = id
self.name = name
self.email = email
}
}
struct CreateUser: Migration {
func prepare(on database: Database) -> EventLoopFuture<Void> {
database.schema("users")
.id()
.field("name", .string, .required)
.field("email", .string, .required)
.create()
}
func revert(on database: Database) -> EventLoopFuture<Void> {
database.schema("users").delete()
}
}
Пример запроса в контроллере:
// Создание пользователя
let user = User(name: "Алексей", email: "alex@example.com")
try await user.save(on: req.db)
// Поиск всех пользователей
let users = try await User.query(on: req.db).all()
// Фильтрация по email
let filtered = try await User.query(on: req.db)
.filter(\.$email == "alex@example.com")
.first()
Важно: Fluent использует асинхронность через EventLoopFuture или async/await (начиная с Vapor 4.60+). Убедитесь, что ваша среда поддерживает Swift 5.5+.
MongoDB в Swift: гибкость документов с MongoKitten
Выбор драйвера
Для MongoDB основная библиотека — MongoKitten. Она поддерживает все современные версии MongoDB, включая Atlas (облачная версия). Альтернатива — MongoSwift от MongoDB Inc., но MongoKitten считается более "свифтовой" по стилю.
Подключение к базе
Добавьте в Package.swift:
.package(url: "https://github.com/OpenKitten/MongoKitten.git", from: "7.0.0")
Пример подключения (для iOS/macOS):
import MongoKitten
let connectionString = "mongodb://localhost:27017/swift_db"
let db = try await MongoDatabase.connect(to: connectionString)
// Получаем коллекцию
let usersCollection = db["users"]
CRUD-операции с документами BSON
MongoKitten работает с типом Document — аналогом словаря:
// Вставка документа
let newUser: Document = [
"name": "Мария",
"email": "maria@example.com",
"age": 28
]
try await usersCollection.insert(newUser)
// Поиск всех документов
let allUsers = try await usersCollection.find().drain()
// Поиск с фильтром
let query: Document = ["age": ["$gt": 25]]
let filteredUsers = try await usersCollection.find(query).drain()
// Обновление
try await usersCollection.updateMany(
where: ["name": "Мария"],
to: ["$set": ["age": 29]]
)
// Удаление
try await usersCollection.deleteOne(where: ["email": "maria@example.com"])
Для работы с Codable используйте расширение:
struct User: Codable {
let name: String
let email: String
let age: Int
}
let user = User(name: "Иван", email: "ivan@example.com", age: 35)
let doc = try BSONEncoder().encode(user)
try await usersCollection.insert(doc)
Сравнение PostgreSQL и MongoDB для Swift-проектов
| Критерий | PostgreSQL (Fluent) | MongoDB (MongoKitten) |
|---|---|---|
| Тип данных | Реляционные, строгая схема | Документы, гибкая схема |
| Производительность | Высокая для сложных JOIN | Высокая для простых запросов |
| Миграции | Встроенные через Fluent | Ручное управление |
| Транзакции | Полная поддержка ACID | Поддержка с версии 4.0 |
| Сложность для Swift | Средняя (требует Vapor) | Низкая (работает standalone) |