Работа с базами данных в Swift: PostgreSQL и MongoDB на практике

Онлайн-тренажер Python для начинающих

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

Начать курс

Введение: Зачем Swift разработчику базы данных?

При разработке нативных приложений под iOS и macOS часто возникает необходимость хранить данные не только локально (Core Data, UserDefaults), но и на удаленном сервере. Это может быть серверная аналитика, логгирование, синхронизация между устройствами или полноценный бэкенд для приложения. Два самых популярных типа баз данных — реляционные (PostgreSQL) и документоориентированные (MongoDB).

В этой статье мы разберем, как подключиться к PostgreSQL и MongoDB из Swift-приложения, используя популярные библиотеки и драйверы. Особое внимание уделим практике: установке зависимостей, написанию запросов и обработке ошибок.

1. Работа с PostgreSQL из Swift

PostgreSQL — мощная реляционная СУБД, идеально подходящая для проектов, где важна целостность данных и сложные SQL-запросы. В Swift мы можем работать с PostgreSQL двумя основными способами:

  • Через ORM Fluent (часть фреймворка Vapor) — высокоуровневый подход, удобный для веб-приложений.
  • Напрямую через драйвер (например, PostgresNIO) — низкоуровневый контроль, подходит для iOS/macOS приложений.

Рассмотрим второй вариант, так как он не требует Vapor и подходит для обычных приложений.

1.1. Подключение к PostgreSQL через PostgresNIO

Добавьте зависимость в Package.swift:

dependencies: [
    .package(url: "https://github.com/vapor/postgres-nio.git", from: "1.18.0")
]

Пример подключения и выполнения запроса:

import PostgresNIO
import NIOCore
import NIOPosix

func queryPostgres() async throws {
    let eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 1)
    defer { try? eventLoopGroup.syncShutdownGracefully() }

    let config = PostgresConnection.Configuration(
        host: "localhost",
        port: 5432,
        username: "swift_user",
        password: "secret",
        database: "test_db",
        tls: .disable
    )

    let connection = try await PostgresConnection.connect(
        on: eventLoopGroup.next(),
        configuration: config
    )
    defer { try? connection.close() }

    let rows = try await connection.query("SELECT id, name FROM users LIMIT 5;", logger: nil)
    for try await row in rows {
        let id = try row.decode(Int.self, column: "id")
        let name = try row.decode(String.self, column: "name")
        print("ID: \(id), Name: \(name)")
    }
}

Этот код устанавливает соединение с локальным сервером PostgreSQL, выполняет SELECT и выводит результаты. Важно: никогда не храните пароли в коде — используйте переменные окружения или Keychain.

1.2. Вставка данных с параметрами

Для защиты от SQL-инъекций используйте параметризованные запросы:

let name = "Alice"
let age = 30
try await connection.query(
    "INSERT INTO users (name, age) VALUES ($1, $2);",
    params: [.string(name), .int(age)],
    logger: nil
)

2. Работа с MongoDB из Swift

MongoDB — NoSQL база данных, хранящая данные в виде JSON-подобных документов (BSON). Для Swift существует отличный драйвер MongoSwift.

2.1. Установка MongoSwift

Добавьте в Package.swift:

dependencies: [
    .package(url: "https://github.com/mongodb/mongo-swift-driver.git", from: "1.3.0")
]

2.2. Подключение и CRUD операции

Пример подключения к локальной MongoDB и вставки документа:

import MongoSwift

func mongoExample() async throws {
    let client = try MongoClient("mongodb://localhost:27017")
    defer { try? client.syncClose() }

    let db = client.db("test_database")
    let collection = db.collection("users")

    // Вставка документа
    let document: Document = ["name": "Bob", "age": 25, "city": "Moscow"]
    let insertResult = try await collection.insertOne(document)
    print("Inserted document ID: \(insertResult?.insertedID ?? "")")

    // Поиск
    let query: Document = ["name": "Bob"]
    if let found = try await collection.findOne(query) {
        print("Found: \(found)")
    }

    // Обновление
    let update: Document = ["$set": ["age": 26]]
    try await collection.updateOne(filter: query, update: update)

    // Удаление
    try await collection.deleteOne(query)
}

Обратите внимание: MongoSwift использует BSON-документы, которые в Swift представлены типом Document (словарь с особыми правилами сериализации).

2.3. Работа с Codable (MongoKitten)

Если вы хотите использовать нативные Swift-структуры с Codable, рекомендую библиотеку MongoKitten. Она предоставляет более «свифтовый» интерфейс:

import MongoKitten

struct User: Codable {
    let _id: ObjectId
    var name: String
    var age: Int
}

func mongoKittenExample() async throws {
    let db = try await MongoDatabase.connect(to: "mongodb://localhost:27017/test_db")

    let users = db["users"]

    // Вставка
    let newUser = User(_id: ObjectId(), name: "Charlie", age: 28)
    try await users.insert(newUser)

    // Поиск с фильтром
    let cursor = try await users.find(["age": ["$gt": 20]], as: User.self)
    for try await user in cursor {
        print("User: \(user.name), \(user.age)")
    }
}

3. Сравнение PostgreSQL и MongoDB для iOS/macOS

Выбор между SQL и NoSQL зависит от задачи. Сведем ключевые отличия в таблицу:

  • PostgreSQL — строгая схема, транзакции, сложные JOIN-запросы. Идеально для финансовых систем, аналитики, любых данных с четкой структурой.
  • MongoDB — гибкая схема, быстрая разработка, встроенная репликация. Подходит для логов, пользовательских профилей, каталогов товаров.

Для iOS-приложений, которые общаются с сервером через REST API, база данных обычно находится на сервере. Но если вы пишете серверную часть на Swift (например, с Vapor), то обе СУБД поддерживаются отлично.

3.1. Производительность и асинхронность

Оба драйвера (PostgresNIO и <

Блоги

Рекомендаций по книгам