commit 699dd0d18f162cbbc6bad12f2eddb271e1ee63c9 Author: litoq Date: Tue Oct 28 15:59:56 2025 +0300 Add initial documentation for MongoDB, Neo4j, pgAdmin, PostgreSQL, and Redis in Docker diff --git a/README.md b/README.md new file mode 100644 index 0000000..cb394f6 --- /dev/null +++ b/README.md @@ -0,0 +1,93 @@ +# Практикум: «Работа с реляционными и нереляционными СУБД» + + + +#### Установка Docker Desktop на Windows + +- Требования: + - Windows 10 21H2/22H2 (19044/19045) или Windows 11 + - Включенная виртуализация в BIOS/UEFI (Intel VT-x/AMD-V) + - Рекомендовано: WSL 2 + +- Включить компоненты Windows (PowerShell от имени администратора): + ```powershell + dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all /norestart + dism.exe /online /enable-feature /featurename:VirtualMachinePlatform /all /norestart + ``` + Перезагрузите компьютер. + +- Установить ядро WSL2 (если требуется): + ```powershell + wsl --install --no-distribution + wsl --update + ``` + +- Скачать и установить Docker Desktop: см. страницу загрузки [Docker Desktop for Windows](https://www.docker.com/products/docker-desktop/). Во время установки оставьте галочку «Use WSL 2 based engine». + +- Первый запуск и базовые настройки: + - Войти с Docker ID (или пропустить для локальной работы) + - Settings → General: убедитесь, что «Use the WSL 2 based engine» включен + - Settings → Resources → WSL Integration: включите интеграцию для нужных дистрибутивов WSL + +- Проверка установки: + ```powershell + docker version + docker run hello-world + docker run --rm -it alpine:3.20 echo "Docker OK" + ``` + +## PostgreSQL with Docker + +- **Установите Docker Desktop**: Убедитесь, что Docker установлен и запущен на вашем компьютере. + +- **Скачать образ Postgres**: + ```bash + docker pull postgres:16 + ``` + +- **Запустить контейнер PostgreSQL**: + ```bash + docker run --name pg-local -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=postgres -e POSTGRES_DB=appdb -p 5432:5432 -v pgdata:/var/lib/postgresql/data -d postgres:16 + ``` + +- **Проверить, что контейнер запущен**: + ```bash + docker ps + ``` + +- **Подключение к PostgreSQL**: + - С хоста через psql (Windows PowerShell, macOS, Linux): + ```bash + psql -h localhost -p 5432 -U postgres -d appdb + ``` + При запросе пароля введите: `postgres`. + - URI‑строка подключения (подходит для приложений/GUI‑клиентов): + ``` + postgres://postgres:postgres@localhost:5432/appdb + ``` + - Через psql внутри контейнера: + ```bash + docker exec -it pg-local psql -U postgres -d appdb + ``` + - Параметры для GUI‑клиента (pgAdmin, DBeaver и др.): + - Host: `localhost` + - Port: `5432` + - User: `postgres` + - Password: `postgres` + - Database: `appdb` + - Быстрая проверка подключения (внутри psql): + ```sql + SELECT version(); + ``` + +- **Полезные команды**: + ```bash + # Остановить / запустить / удалить контейнер + docker stop pg-local + docker start pg-local + docker rm -f pg-local + + # Удалить том с данными (необратимо) + docker volume rm pgdata + ``` + diff --git a/mongo.md b/mongo.md new file mode 100644 index 0000000..0511cf0 --- /dev/null +++ b/mongo.md @@ -0,0 +1,111 @@ +# MongoDB: установка и базовое использование + +Краткая инструкция по установке MongoDB на Windows и запуску в Docker, подключению через `mongosh` и базовым операциям. + +## Вариант A: Docker (рекомендуется для практикума) + +```bash +# Запуск MongoDB (порт 27017), создание пользователя root +# Замените StrongPass! на свой пароль + +docker run -d --name mongo -p 27017:27017 -e MONGO_INITDB_ROOT_USERNAME=root -e MONGO_INITDB_ROOT_PASSWORD=StrongPass! -v mongo_data:/data/db mongo:7 +``` + +Подключение `mongosh` (если установлен локально): +```bash +mongosh "mongodb://root:StrongPass!@localhost:27017/?authSource=admin" +``` + +Создание приложения БД/пользователя: +```javascript +use appdb + +db.createUser({ + user: "appuser", + pwd: "AppUserPass!", + roles: [ { role: "readWrite", db: "appdb" } ] +}) +``` + +Проверка записи/чтения: +```javascript +db.items.insertOne({ name: "sensor-1", type: "pressure", value: 28.5 }) +db.items.find() +``` + +Останов/старт/удаление контейнера: +```bash +docker stop mongo && docker start mongo && docker rm -f mongo +``` + +## Полезные команды `mongosh` +```javascript +// Показать базы/коллекции +show dbs +use appdb +show collections + +// CRUD +db.devices.insertMany([{name:"compressor-A", status:"online"},{name:"compressor-B", status:"offline"}]) +db.devices.find({status:"online"}) +db.devices.updateOne({name:"compressor-B"}, {$set: {status:"online"}}) +db.devices.deleteOne({name:"compressor-A"}) + +// Индекс +db.devices.createIndex({status:1}) + +// Фильтры (сравнение, логика, диапазоны) +db.devices.find({status: {$in: ["online", "maintenance"]}}) +db.readings.find({value: {$gte: 10, $lt: 50}}) +db.readings.find({$and: [{type:"pressure"}, {value: {$gt: 100}}]}) + +// Проекция полей (включение/исключение) +db.devices.find({}, {name:1, status:1, _id:0}) + +// Сортировка, лимит, пропуск +db.readings.find({type:"temperature"}).sort({timestamp:-1}).limit(10) +db.readings.find({type:"temperature"}).sort({timestamp:1}).skip(20).limit(10) + +// Составной запрос: фильтр + проекция + сортировка + пагинация +db.devices.find({status:"online"}, {name:1, status:1, _id:0}).sort({name:1}).skip(0).limit(5) + +// Поддокументы/массивы +db.wells.insertOne({name:"Well-1001", sensors:[{type:"pressure", value:2800},{type:"temperature", value:85}]}) +db.wells.find({"sensors.type":"pressure", "sensors.value": {$gt: 2500}}) + + +// Встроенные (embedded) документы: вложенные поля, запросы и обновления +db.wells.insertOne({ + name: "Well-1002", + location: { field: "Permian", coords: { lat: 31.77, lon: -102.39 } }, + equipment: { + compressor: { model: "CMP-900", status: "online" }, + valve: { type: "pressure_relief", lastService: ISODate("2025-10-01") } + } +}) + +// Поиск по вложенным полям (dot-notation) +db.wells.find({ "location.field": "Permian", "equipment.compressor.status": "online" }, { _id:0, name:1 }) + +// Проекция поддокумента +db.wells.find({ name: "Well-1002" }, { _id:0, equipment:1 }) + +// Обновление вложенного поля +db.wells.updateOne( + { name: "Well-1002" }, + { $set: { "equipment.compressor.status": "maintenance" } } +) + +// Добавление нового вложенного поля, если его не было +db.wells.updateOne( + { name: "Well-1002" }, + { $set: { "equipment.sensorHub": { firmware: "1.2.3", ports: 8 } } } +) + +// Удаление вложенного поля +db.wells.updateOne( + { name: "Well-1002" }, + { $unset: { "equipment.valve.lastService": "" } } +) +``` + diff --git a/neo4j.md b/neo4j.md new file mode 100644 index 0000000..abe9d6e --- /dev/null +++ b/neo4j.md @@ -0,0 +1,55 @@ +# Neo4j в Docker: установка и базовое использование + +Краткая инструкция по запуску Neo4j в Docker, подключению к Browser/bolt и базовым операциям. + +## Запуск Neo4j (одной командой) + +```bash +# Откроет порты 7474 (HTTP) + +docker run -d --name neo4j -p 7474:7474 -e NEO4J_AUTH=neo4j/neo4j -v neo4j_data:/data -v neo4j_logs:/logs -v neo4j_import:/var/lib/neo4j/import -v neo4j_plugins:/plugins neo4j:5 +``` + +- Откройте `http://localhost:7474` (Neo4j Browser) +- Подключение по bolt: `bolt://localhost:7687` + +## Управление контейнером + +```bash +docker restart neo4j + +docker stop neo4j + +docker rm -f neo4j +``` + +## Переменные окружения (часто используемые) + +- `NEO4J_AUTH=neo4j/` — пароль пользователя `neo4j` (или `none` для тестов) + + +## Подключение из CLI (cypher-shell) + +Если установлен `cypher-shell` на хосте: +```bash +cypher-shell -u neo4j -p MyStrongPassword! -a bolt://localhost:7687 +``` + +Или из контейнера: +```bash +docker exec -it neo4j cypher-shell -u neo4j -p MyStrongPassword! +``` + +## Базовые команды Cypher (пример) + +```cypher +// Создать узел +CREATE (:Person {name: "Alice", age: 30}); + +// Найти узлы +MATCH (p:Person) RETURN p LIMIT 10; + +// Создать связь +MATCH (a:Person {name:"Alice"}) +CREATE (a)-[:KNOWS]->(:Person {name:"Bob"}); +``` diff --git a/pgadmin.md b/pgadmin.md new file mode 100644 index 0000000..60a14bf --- /dev/null +++ b/pgadmin.md @@ -0,0 +1,46 @@ +# pgAdmin (Docker): установка и подключение к существующему PostgreSQL + +Инструкция по запуску pgAdmin 4 в Docker и подключению к контейнеру Postgres `pg-local`. + +## 1) Запуск pgAdmin в Docker + +- Вариант по умолчанию (порт 5050): +```bash +docker run -d --name pgadmin -e PGADMIN_DEFAULT_EMAIL=admin@example.com -e PGADMIN_DEFAULT_PASSWORD=admin -p 5050:80 -v pgadmin_data:/var/lib/pgadmin dpage/pgadmin4:latest +``` + +- Открыть интерфейс: + - Браузер: http://localhost:5050 + - Войти с значениями `PGADMIN_DEFAULT_EMAIL` и `PGADMIN_DEFAULT_PASSWORD`. + +## 2) Подключение к текущему Postgres (`pg-local`) + +У вас уже запущен контейнер PostgreSQL (см. README): +```bash +docker run --name pg-local -e POSTGRES_USER=postgres -e POSTGRES_PASSWORD=postgres -e POSTGRES_DB=appdb -p 5432:5432 -v pgdata:/var/lib/postgresql/data -d postgres:16 +``` + +### Подключение через опубликованный порт хоста.. +- В pgAdmin: Add New Server → вкладка General: + - Name: `Local Postgres` +- Вкладка Connection: + - Host: `localhost` (если pgAdmin установлен на хосте) + - Host: `host.docker.internal` (если pgAdmin запущен в Docker без общей сети) + - Port: `5432` + - Maintenance DB: `appdb` (или `postgres`) + - Username: `postgres` + - Password: `postgres` + - Save Password: включить (по желанию) +- Сохранить. Подключение установится сразу. + +Примечание: pgAdmin открыт в вашем браузере, поэтому доступ к `localhost:5432` идёт с вашей машины. + +## 3) Проверка соединения +После добавления сервера в pgAdmin, раскройте дерево: +- Servers → ваш сервер → Databases → `appdb` → Schemas → `public` → Tables +- Откройте Query Tool и выполните: +```sql +SELECT version(); +SELECT current_database(), current_user, now(); +``` + diff --git a/postgres.md b/postgres.md new file mode 100644 index 0000000..b8c07bc --- /dev/null +++ b/postgres.md @@ -0,0 +1,314 @@ +# Работа с PostgreSQL + +Минимальные команды для работы с одной таблицей: подключение, создание с первичным ключом, CRUD и основные команды ALTER. + +## Подключение (контейнер Docker) + +```bash +docker exec -it pg-local psql -U postgres -d appdb +``` +## Важные slash-команды psql + +```psql +\? -- помощь по psql +\l -- список баз данных +\c appdb -- подключиться к базе appdb +\dt -- список таблиц +\du -- список ролей/пользователей +\dn -- список схем +\d contacts -- описание таблицы contacts +\i file.sql -- выполнить SQL-скрипт из файла +\q -- выход +``` +Выйти: `\q`. + +## Рекомендации по именованию (best practices) + +- Таблицы и столбцы: `snake_case`, английские названия; будьте последовательны (единственное или множественное число — выберите и придерживайтесь). +- Первичный ключ: как правило `id` типа `BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY`. +- Внешние ключи: `_id`, тот же тип, что и PK ссылочной таблицы. +- Метки времени: `created_at`, `updated_at` типа `TIMESTAMPTZ`; задавайте `DEFAULT now()` и `NOT NULL`. +- Уникальные ограничения: `uq___[_]`. +- Первичный ключ: `pk_
` (имя создаётся автоматически, но можно переопределить). +- Внешние ключи: `fk_
__`. +- Индексы: `idx_
__[_]`. + +Пример (рекомендуемая версия таблиц): +```sql +CREATE TABLE contacts ( + id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + full_name TEXT NOT NULL, + email TEXT, + department_id BIGINT, + created_at TIMESTAMPTZ NOT NULL DEFAULT now(), + updated_at TIMESTAMPTZ NOT NULL DEFAULT now(), + CONSTRAINT uq_contacts__email UNIQUE (email) +); + +CREATE TABLE departments ( + department_id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + name TEXT NOT NULL, + CONSTRAINT uq_departments__name UNIQUE (name) +); + +ALTER TABLE contacts + ADD CONSTRAINT fk_contacts__departments + FOREIGN KEY (department_id) + REFERENCES departments(department_id) + ON UPDATE CASCADE + ON DELETE SET NULL; + +-- Индексы +CREATE INDEX idx_contacts__department_id ON contacts(department_id); +CREATE INDEX idx_contacts__full_name ON contacts(full_name); +``` + +## Создание таблицы (с первичным ключом) + +```sql +CREATE TABLE contacts ( + id SERIAL PRIMARY KEY, + full_name TEXT NOT NULL, + email TEXT UNIQUE, + created_at TIMESTAMPTZ NOT NULL DEFAULT now() +); +``` + +## Операции CRUD + +```sql +-- Создать запись +INSERT INTO contacts (full_name, email) +VALUES ('Alice Johnson', 'alice@example.com'); + +-- Прочитать записи +SELECT id, full_name, email, created_at +FROM contacts +ORDER BY id +LIMIT 10; + +-- Обновить запись +UPDATE contacts +SET email = 'alice@newmail.com' +WHERE id = 1; + +-- Удалить запись +DELETE FROM contacts +WHERE id = 1; +``` + +### Работа с NULL + +```sql +-- Вставить запись без email (NULL) +INSERT INTO contacts (full_name, email) VALUES ('No Email User', NULL); + +-- Найти записи с отсутствующим email +SELECT id, full_name, email FROM contacts WHERE email IS NULL; + +-- Найти записи, где email указан +SELECT id, full_name, email FROM contacts WHERE email IS NOT NULL; + +-- Подставить значение по умолчанию, если email NULL +SELECT id, full_name, COALESCE(email, 'no-email@example.com') AS safe_email +FROM contacts; + +``` + +## Основные команды ALTER TABLE + +```sql +-- Добавить столбец +ALTER TABLE contacts ADD COLUMN phone TEXT; + +-- Переименовать столбец +ALTER TABLE contacts RENAME COLUMN phone TO phone_number; + +-- Удалить столбец +ALTER TABLE contacts DROP COLUMN phone_number; + +-- Изменить тип столбца (пример: TEXT -> VARCHAR) +ALTER TABLE contacts ALTER COLUMN full_name TYPE VARCHAR(200); + +-- Добавить первичный ключ в существующую таблицу (если отсутствует) +ALTER TABLE contacts ADD COLUMN id SERIAL; +ALTER TABLE contacts ADD PRIMARY KEY (id); + +-- Удалить первичный ключ +ALTER TABLE contacts DROP CONSTRAINT contacts_pkey; + +-- Переименовать таблицу +ALTER TABLE contacts RENAME TO people; +``` + +## Работа с несколькими таблицами (две) + +Добавим таблицу `departments` и внешний ключ из `contacts` на `departments`. + +```sql +-- Создать таблицу отделов +CREATE TABLE departments ( + department_id SERIAL PRIMARY KEY, + name TEXT NOT NULL UNIQUE +); + +-- Вернуть имя таблицы people обратно, если переименовывали ранее +ALTER TABLE IF EXISTS people RENAME TO contacts; + +-- Добавить внешний ключ на departments +ALTER TABLE contacts ADD COLUMN department_id INT; +ALTER TABLE contacts + ADD CONSTRAINT contacts_department_fk + FOREIGN KEY (department_id) + REFERENCES departments(department_id) + ON UPDATE CASCADE + ON DELETE SET NULL; +``` + +Пример данных: +```sql +INSERT INTO departments (name) VALUES ('Sales'), ('Engineering'), ('HR'); + +UPDATE contacts SET department_id = 1 WHERE id = 1; -- Alice -> Sales +-- При необходимости добавьте больше контактов аналогично +``` + +### Примеры JOIN + +```sql +-- INNER JOIN: только совпадающие записи +SELECT c.id, c.full_name, d.name AS department +FROM contacts c +JOIN departments d ON d.department_id = c.department_id; + +-- LEFT JOIN: все контакты, даже без отдела +SELECT c.id, c.full_name, d.name AS department +FROM contacts c +LEFT JOIN departments d ON d.department_id = c.department_id; + +-- RIGHT JOIN: все отделы, даже без контактов +SELECT c.id, c.full_name, d.name AS department +FROM contacts c +RIGHT JOIN departments d ON d.department_id = c.department_id; + +-- FULL OUTER JOIN: объединение LEFT и RIGHT +SELECT c.id, c.full_name, d.name AS department +FROM contacts c +FULL JOIN departments d ON d.department_id = c.department_id; +``` + +### UNION и INTERSECT + +```sql +-- UNION: объединить результаты (уникальные строки) +SELECT full_name AS item FROM contacts +UNION +SELECT name AS item FROM departments; + +-- INTERSECT: пересечение множеств +-- (искусственный пример: найдём такие строки, где имя контакта совпадает с названием отдела) +SELECT full_name FROM contacts +INTERSECT +SELECT name FROM departments; +``` + +### Оконные функции (window functions) на примере компаний нефти и газа + +Создадим отдельную таблицу `companies` с повторяющимися данными для примеров. + +```sql +CREATE TABLE companies ( + id BIGINT GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, + company_name TEXT NOT NULL, + sector TEXT NOT NULL, -- 'Oil' | 'Gas' + country TEXT NOT NULL, -- страна регистрации + revenue_usd NUMERIC(14,2) NOT NULL, -- выручка + employees INT NOT NULL, -- число сотрудников + founded_year INT, -- год основания (может повторяться) + created_at TIMESTAMPTZ NOT NULL DEFAULT now() +); + +INSERT INTO companies (company_name, sector, country, revenue_usd, employees, founded_year) VALUES + ('PetroOne', 'Oil', 'USA', 1200000.00, 5000, 1980), + ('GasPrime', 'Gas', 'USA', 800000.00, 3200, 1990), + ('NordOil', 'Oil', 'Norway',950000.00, 2100, 1975), + ('EuroGas', 'Gas', 'Norway',400000.00, 1500, 2001), + ('OilAsia', 'Oil', 'UAE', 2200000.00, 9000, 1970), + ('GasEast', 'Gas', 'UAE', 1300000.00, 4800, 1988), + ('LatOil', 'Oil', 'Brazil', 500000.00, 1200, 2005), + ('SouthGas', 'Gas', 'Brazil', 350000.00, 900, 2005), + ('OilAsia-2', 'Oil', 'UAE', 1600000.00, 6000, 1970); -- повторяющиеся страна/год/sector +``` + +Группировки, фильтрация (HAVING), сортировка и LIMIT: + +```sql +-- Выручка и среднее число сотрудников по сектору +SELECT sector, + SUM(revenue_usd) AS total_revenue, + AVG(employees)::INT AS avg_employees +FROM companies +GROUP BY sector +HAVING SUM(revenue_usd) > 1000000 -- оставить только сектора с суммарной выручкой > 1 млн +ORDER BY total_revenue DESC +LIMIT 10; + +-- По стране и сектору +SELECT country, sector, + COUNT(*) AS num_companies, + SUM(revenue_usd) AS total_revenue +FROM companies +GROUP BY country, sector +ORDER BY total_revenue DESC, country; +``` + +Примеры оконных функций: + +```sql +-- Нумерация компаний внутри сектора по выручке (от большей к меньшей) +SELECT company_name, sector, revenue_usd, + ROW_NUMBER() OVER (PARTITION BY sector ORDER BY revenue_usd DESC) AS rn_in_sector +FROM companies +ORDER BY sector, rn_in_sector; + +-- Ранги: RANK (с пропусками), DENSE_RANK (без пропусков) внутри сектора +SELECT company_name, sector, revenue_usd, + RANK() OVER (PARTITION BY sector ORDER BY revenue_usd DESC) AS rnk, + DENSE_RANK() OVER (PARTITION BY sector ORDER BY revenue_usd DESC) AS drnk +FROM companies +ORDER BY sector, rnk; + +-- Сумма и среднее по стране (окно PARTITION BY) +SELECT company_name, country, revenue_usd, + SUM(revenue_usd) OVER (PARTITION BY country) AS country_revenue_total, + AVG(revenue_usd) OVER (PARTITION BY country) AS country_revenue_avg +FROM companies +ORDER BY country, revenue_usd DESC; + +-- Скользящее среднее по выручке внутри сектора (окно 1 предыдущая, текущая, 1 следующая) +SELECT company_name, sector, revenue_usd, + AVG(revenue_usd) OVER ( + PARTITION BY sector + ORDER BY revenue_usd + ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING + ) AS moving_avg_in_sector +FROM companies +ORDER BY sector, revenue_usd; + +-- Процентильные ранги и квартиль (NTILE) +SELECT company_name, sector, revenue_usd, + PERCENT_RANK() OVER (PARTITION BY sector ORDER BY revenue_usd) AS percent_rank_in_sector, + CUME_DIST() OVER (PARTITION BY sector ORDER BY revenue_usd) AS cume_dist_in_sector, + NTILE(4) OVER (PARTITION BY sector ORDER BY revenue_usd) AS quartile_in_sector +FROM companies +ORDER BY sector, revenue_usd; + +-- LAG/LEAD: сравнение с соседями по выручке внутри сектора +SELECT company_name, sector, revenue_usd, + LAG(revenue_usd) OVER (PARTITION BY sector ORDER BY revenue_usd) AS prev_revenue, + LEAD(revenue_usd) OVER (PARTITION BY sector ORDER BY revenue_usd) AS next_revenue +FROM companies +ORDER BY sector, revenue_usd; +``` + + diff --git a/redis.md b/redis.md new file mode 100644 index 0000000..1c2f014 --- /dev/null +++ b/redis.md @@ -0,0 +1,173 @@ +# Redis в Docker: установка и базовые команды + +Краткая инструкция по запуску Redis в Docker и использованию `redis-cli`. + +## Установка/запуск Redis в Docker + +- Запустить Redis (порт 6379): +```bash +docker run -d --name redis -p 6379:6379 redis:7 +``` + +- Перезапуск/остановка/удаление: +```bash +docker restart redis +``` +```bash +docker stop redis +``` +```bash +docker rm -f redis +``` + +## Подключение к Redis + +- Из контейнера (встроенный `redis-cli`): +```bash +docker exec -it redis redis-cli +``` + +- С хоста (если установлен `redis-cli`): +```bash +redis-cli -h 127.0.0.1 -p 6379 +``` + +- Проверка доступности: +```bash +redis-cli -h 127.0.0.1 -p 6379 PING +# Ответ: PONG +``` + +## Базовые команды (ключ-значение) + +```redis +# Имена скважин +SET well:1001:name "Well-1001" +GET well:1001:name + +# Счетчики добычи (баррели нефти) +SETNX counters:production:well:1001:bbl 0 +INCR counters:production:well:1001:bbl +INCRBY counters:production:well:1001:bbl 250 +DECR counters:production:well:1001:bbl + +# Массовая запись/чтение параметров месторождения +MSET field:permian:name Permian field:permian:country USA field:permian:type oil +MGET field:permian:name field:permian:country field:permian:type + +# Удаление и проверка существования +DEL field:permian:type +EXISTS well:1001:name +TTL counters:production:well:1001:bbl +``` + +## Время жизни/истечение + +```redis +# Кэш телеметрии датчика давления (истекает через 5 минут) +SET sensor:well:1001:pressure:psi "2850" EX 300 + +# Продлить TTL еще на 60 секунд +EXPIRE sensor:well:1001:pressure:psi 60 + +# Сделать запись постоянной +PERSIST sensor:well:1001:pressure:psi +``` + +## Поиск ключей и очистка + +```redis +KEYS well:* +``` + +## Структуризация команд + +### 1) Простые типы: строки и числа + +```redis +# Строки состояния +SET well:1001:status "online" +GET well:1001:status + +# Множественная запись паспортных данных скважины +MSET well:1001:field Permian well:1001:type oil well:1001:depth_m 3200 +MGET well:1001:field well:1001:type well:1001:depth_m + +# Только если ключ не существует (инициализация счетчика газа, тыс. куб. футов) +SETNX counters:gas:well:1001:mcf 0 + +# Инкременты/декременты +INCR counters:gas:well:1001:mcf +INCRBY counters:gas:well:1001:mcf 500 +DECR counters:gas:well:1001:mcf + +# Полезное: журнал операций +APPEND ops:log "start_pump;" +STRLEN ops:log +GETSET last:ops:timestamp "2025-10-28T10:00:00Z" +DEL ops:log well:1001:status +EXISTS counters:gas:well:1001:mcf +``` + +### 2) Списки (queues/стэки) + +```redis +# Очередь работ по обслуживанию +LPUSH jobs:maintenance well:1001:inspect well:1002:replace_valve +RPUSH jobs:maintenance well:1003:calibrate_sensor + +# Изъятие задач +LPOP jobs:maintenance +RPOP jobs:maintenance + +# Диапазон и метаданные +LRANGE jobs:maintenance 0 -1 +LLEN jobs:maintenance +LINDEX jobs:maintenance 0 + +# Блокирующие операции (ожидание новой задачи) +BLPOP jobs:maintenance 5 +BRPOP jobs:maintenance 5 + +# Удаление конкретной задачи +LREM jobs:maintenance 0 well:1002:replace_valve +``` + +### 3) Хэши (похожие на объекты) + +```redis +# Паспорт скважины +HSET well:1001 name "Well-1001" field "Permian" status "online" depth_m 3200 +HGET well:1001 name +HMGET well:1001 field status depth_m +HGETALL well:1001 + +# Управление полями +HDEL well:1001 status +HEXISTS well:1001 field +HLEN well:1001 + +# Счетчики в хэше (например, количество запусков насоса) +HINCRBY well:1001 metrics:pump_starts 1 +``` + +### 4) Множества (уникальные элементы, без порядка) + +```redis +# Скважины по месторождениям +SADD field:permian:wells 1001 1002 +SADD field:west_siberia:wells 1002 1003 +SMEMBERS field:permian:wells +SCARD field:west_siberia:wells + +# Операции множеств (пересечения/объединения между полями) +SUNION field:permian:wells field:west_siberia:wells # 1001 1002 1003 +SINTER field:permian:wells field:west_siberia:wells # 1002 +SDIFF field:permian:wells field:west_siberia:wells # 1001 + +# Теги оборудования на скважине +SADD well:1001:tags oil onshore artificial_lift +SISMEMBER well:1001:tags oil +``` + +> Примечание: отсортированные множества (ZSET) и другие структуры (Streams, Bitmaps, HyperLogLog) можно добавить позже по мере необходимости.