Статьи

Ускоренный курс про покемонов на CouchDB

В этом уроке мы рассмотрим работу с CouchDB , базой данных NoSQL от Apache. В этом руководстве основное внимание будет уделено практической стороне, поэтому мы не будем рассказывать о том, для чего CouchDB хорош, как его устанавливать, зачем его использовать и т. Д. Мы сосредоточимся на том, как выполнять операции с базой данных через HTTP-API CouchDB и как работать с ним в PHP, закладывая основу для будущих, более сложных сообщений.

Мы предполагаем, что вы уже установили CouchDB и Futon (веб-консоль администрирования CouchDB) на своем компьютере . Если вы хотите следовать, мы рекомендуем вам использовать нашу коробку HI .

CouchDB Logo

Примечание: для простоты мы будем ссылаться на нашу локальную машину с localhost С Homestead Improved это просто вопрос перечисления портов, которые вы хотите перенаправить, в конфигурационном файле Homestead.yaml

Создание базы данных

Чтобы создать новую базу данных CouchDB, посетите Futon по адресу http://localhost:5984/_utils/ Вы увидите следующий интерфейс:

футон

Нажмите на создание базы данных , введите имя базы данных и нажмите на создание, чтобы создать базу данных.

После создания вы увидите следующий экран:

база данных couchdb

Обратите внимание, что есть только опция для создания нового документа. В CouchDB документ является эквивалентом строки таблицы в реляционной базе данных. Итак, как мы создаем таблицы?

Если вы пришли из базы данных NoSQL, такой как MongoDB, первое, что вам нужно знать, это то, что в CouchDB нет такой вещи, как коллекции или таблицы. Есть только документы. Однако это не означает, что вы можете хранить только один тип данных для каждой базы данных. Поскольку каждый документ, который вы создаете в CouchDB, не принадлежит ни одной таблице, вы можете иметь различную структуру для каждого типа данных. Например, если вы хотите сохранить пользовательские данные, вы можете иметь структуру, подобную следующей:

 {
    "id": 123,
    "fname": "doppo",
    "lname": "kunikida",
    "pw": "secret",
    "hobbies": ["reading", "sleeping"]
}

С другой стороны, если вы хотите хранить информацию в блоге, вы можете иметь следующую структуру:

 {
    "title": "The big brown fox",
    "author": "fox",
    "text": "Lorem ipsum dolor sit amet, consectetur adipisicing elit. Earum, quasi in id voluptates. Natus qui iure corporis ea voluptatem eius, possimus optio modi facere blanditiis quo, sequi suscipit eos nostrum.",
    "publish_date": "2016-07-07"
}

Чтобы упростить запрос к определенному типу документа (например, пользователи, сообщения в блоге), вы можете добавить поле для хранения типа документа:

 {
    "id": "123",
    "fname": "doppo",
    "lname": "kunikida",
    "pw": "secret",
    "hobbies": ["reading", "sleeping"],
    "type": "users"
}

Обратите внимание, что type Это используется только для удобства.

Разговор с HTTP API

Поскольку CouchDB предоставляет HTTP API, мы также можем использовать curl

 curl -X PUT http://localhost:5984/<database name>

Выполнение вышеупомянутой команды должно вернуть следующее:

 {"ok":true}

CouchDB возвращает строки JSON в качестве ответа. Это делает его очень простым в использовании как в браузере, так и на стороне сервера.

Мы рекомендуем Postman для экспериментов во время этого урока, так как он позволяет легко общаться с HTTP API CouchDB. Если вы новичок в Postman, вам может помочь это введение: создание и тестирование API стало проще с Postman .

Создание новых документов

Чтобы создать новые документы, нам нужно отправить запрос POST

 http://localhost:5984/test_couch

При отправке запроса в CouchDB всегда следует помнить следующее:

  • Укажите Content-Typeapplication/jsonPOSTPUTDELETE
  • Оберните строки в двойные кавычки.

Вот пример запроса для создания нового документа:

Создание нового документа с почтальоном

Массовая вставка

Чтобы вставить несколько строк данных в одном запросе:

Массовая вставка через Почтальон

Мы также будем использовать эти данные, когда поиграемся с получением документов позже. Если вы хотите следовать, вот данные для вставки: couchdb-bulk.json

Получение документов

Попробуем восстановить все документы, которые в данный момент хранятся в базе данных:

Получение всех документов

По умолчанию CouchDB возвращает только уникальный идентификатор, ключ (такой же, как уникальный идентификатор) и значение, которое по умолчанию является объектом, содержащим номер последней редакции (уникальная строка, представляющая конкретную версию документа). Мы поговорим о ревизиях позже.

Чтобы получить данные, которые мы сохранили ранее, мы должны указать include_docstrue

 http://localhost:5984/test_couch/_all_docs?include_docs=true

Получение конкретных документов

В CouchDB вы можете получить определенные документы, используя идентификатор документа:

 http://localhost:5984/test_couch/8939b0d23a0ba7a5ed55fd981d0010a0?include_docs=true

Вы также можете получить конкретную версию документа, указав номер редакции через параметр запроса rev

 http://localhost:5984/test_couch/8939b0d23a0ba7a5ed55fd981d0010a0?rev=1-1841dec358ff29eca8c42a52f1c2a1d0&include_docs=true

Каждый раз, когда вы создаете новый документ или обновляете существующий, CouchDB генерирует уникальный номер редакции. Затем он присваивает его этому состоянию документа. Например, если вы добавите новое поле с именем skillskill Он делает это каждый раз, когда вы вносите изменения (например, обновляете значение для определенного поля, удаляете поле, переименовываете поле, добавляете новое поле) в документ. Это действительно полезно, если вам нужно сохранить исторические данные.

Если вы обращаетесь к конкретному документу в Futon, вы также можете перемещаться по его предыдущим версиям:

Доступ к ревизиям

Взгляды

Представления позволяют нам извлекать конкретные данные из базы данных и упорядочивать их особым образом.

Чтобы создать представление, зайдите в базу данных на Futon и в раскрывающемся меню в правом верхнем углу выберите временное представление . Это покажет вам следующий интерфейс:

создать временный вид

В оставшейся части урока мы будем использовать данные, которые мы вставили ранее.

Сначала давайте посмотрим на функцию, которая фильтрует Pokemon по их тренеру:

 function(doc) {
  emit(doc.trainer, doc.name);
}

Добавьте эту функцию в качестве значения для функции карты . Эта функция использует встроенный метод emit Ключ — тот, который используется для фильтрации документов, а значение — это значение, которое мы хотим вернуть для каждой строки.

Вот ответ, который мы получаем, когда выполняем функцию:

посмотреть ответ

Как видите, он просто возвращает все. Это потому, что мы не указали значение, которое будет использоваться в качестве фильтра. Чтобы увидеть эту функцию в действии, нам нужно сохранить вид, нажав кнопку « Сохранить как» .

сохранить вид

Это попросит у нас название проектного документа и название вида. Вы можете думать о проектных документах как о коллекции связанных видов. Мы назовем его pokemon, поскольку документы, над которыми мы работаем, в основном касаются данных Pokemon. Что касается представления, мы назовем его в честь того, что он делает: filter_by_trainer

Теперь давайте сделаем запрос к представлению, которое мы только что создали:

 http://localhost:5984/test_couch/_design/pokemon/_view/filter_by_trainer?key="Ash"

Это вернет следующие результаты:

фильтр по результатам тренера

То, что вы передадите в качестве значения параметра key

Фильтрация по полю массива

Что если нам нужно отфильтровать по полю массива, такому как поле type
Для этого нам нужно будет перебрать все элементы массива и выдать документы из цикла следующим образом:

 function(doc) {
  for(var x = 0; x < doc.type.length; x++){
     emit(doc.type[x], doc.name); 
  }
}

Сохраните это представление как filter_by_typeGET

 http://localhost:5984/test_couch/_design/pokemon/_view/filter_by_type?key="Fire"

Это вернет всех покемонов с «Огнем» как один из их типов:

фильтр по типу ответа

Сортировка и ограничение результатов

Чтобы отсортировать результаты, все, что вам нужно сделать, это выделить поле, с которым вы хотите отсортировать. В этом случае мы будем использовать owned

 function(doc){
   emit(doc.owned, doc.name);  
}

Сохраните это представление как order_by_owned

 http://localhost:5984/test_couch/_design/pokemon/_view/sort_by_owned

По умолчанию CouchDB возвращает документы в порядке возрастания, поэтому первыми идут те покемоны, которым принадлежал самый длинный. Чтобы отсортировать документы в порядке убывания, укажите в качестве параметра запроса descending=true

 http://localhost:5984/test_couch/_design/pokemon/_view/sort_by_owned?descending=true

Чтобы ограничить количество возвращаемых документов, установите limit

 http://localhost:5984/test_couch/_design/pokemon/_view/sort_by_owned?limit=5

Группировка результатов

Если вы хотите вернуть количество покемонов, которое есть у каждого уникального тренера, нам нужно использовать функцию уменьшения. Функция Reduce позволяет нам выполнять операции группировки и агрегирования результатов, возвращаемых функцией map. CouchDB поставляется с тремя встроенными функциями сокращения: _count_sum_stats Мы рассмотрим _count_count

Мы можем использовать функцию function(doc) {
emit(doc.trainer, doc.name);
}
Начните с добавления следующей функции карты:

 _count

Для функции сокращения group_by_trainer Затем сохраните вид с именем http://localhost:5984/test_couch/_design/pokemon/_view/group_by_trainer?group=true

Сделайте запрос на следующий URL:

 group=true

Установка {
"rows": [
{
"key": null,
"value": 9
}
]
}

 group=true

Приведенный выше результат показывает только общее количество документов, которые в данный момент находятся в базе данных. Это означает, что функция сокращения считала весь набор результатов, возвращаемый функцией карты, одной группой.

Установка doc.trainer{
"rows": [
{
"key": "Ash",
"value": 5
},
{
"key": "Brock",
"value": 1
},
{
"key": "Misty",
"value": 2
},
{
"key": "Team Rocket",
"value": 1
}
]
}

 PUT

Обновление документов

Чтобы обновить документы, мы отправляем запрос DELETE

обновить документ

На основе приведенного выше снимка экрана видно, что CouchDB не поддерживает обновление определенных полей: вам нужно извлечь существующие данные, выполнить обновления и затем отправить обновленные данные обратно в базу данных.

Удаление документов

Чтобы удалить документ, выполните запрос http://localhost:5984/test_couch/<Document ID>?rev=<Revision ID>

 GET

Он имеет тот же формат, что и URL-адрес для извлечения документа, и поскольку мы передаем идентификатор редакции, это означает, что мы можем также удалить определенные редакции документа (отменить функцию кого-либо?).

Работа с PHP

Есть два способа работы с CouchDB в PHP. Первый — через Guzzle , а другой — через библиотеку, специально созданную для работы с CouchDB, например, CouchDB Client от Doctrine. В этом разделе мы рассмотрим, как работать с каждой из этих библиотек.

пропивать

При получении данных мы должны использовать запрос query<?php
require 'vendor/autoload.php';

use GuzzleHttp\Client;

$client = new GuzzleHttp\Client([‘base_uri’ => ‘http://localhost:5984’]);

$response = $client>request(‘GET’, ‘/test_couch/_all_docs’, [
‘query’ => [
‘include_docs’ => ‘true’
]
]);

$json = $response>getBody()>getContents();
$data = json_decode($json, true);

 $docs = [
    'docs' => [
        [
            "name" => "Tangela",
            "type" => ["Grass"],
            "trainer" => "Erika",
            "gender" => "f",
            "owned" => "1999-07-27"
        ],
        [
            "name" => "Wobbuffet",
            "type" => ["Psychic"],
            "trainer" => "Elesa",
            "gender" => "m",
            "owned" => "2014-09-09"
        ],
        [
            "name" => "Gogoat",
            "type" => ["Grass"],
            "trainer" => "Ramos",
            "gender" => "m",
            "owned" => "2015-10-17"
        ]
    ]
];

$client->request('POST', '/test_couch/_bulk_docs', [
    'headers' => [
        'Content-Type' => 'application/json'
    ],
    'body' => json_encode($docs)
]);

Далее давайте сделаем массовую вставку:

 PUT

Из приведенного выше кода видно, что применяются те же правила.

Чтобы обновить документ, используйте запрос body А затем передайте измененный документ в $doc = [
'_rev' => '2-ff235602e45c46aed0f8834c32817546',
'name' => 'Blastoise',
'type' => ['Water'],
'gender' => 'm',
'trainer' => 'Ash',
'owned' => '1999-05-21'
];

$client>request(‘PUT’, ‘/test_couch/5a6a50b7c98499a4d8d69d4bfc00029a’, [
‘headers’ => [
‘Content-Type’ => ‘application/json’
],
‘body’ => json_encode($doc)
]);

 DELETE

Чтобы удалить документ, используйте запрос query$client->request('DELETE', '/test_couch/7c7f800ee10a39f512a456339e0019f3', [
'query' => [
'rev' => '1-967a00dff5e02add41819138abb3284d'
]
]);

 CouchDBClient

Doctrine CouchDB Client

Далее давайте посмотрим, как работать с базой данных CouchDB с клиентом CouchDB .

Сначала мы должны создать новый экземпляр <?php
require 'vendor/autoload.php';

$client = \Doctrine\CouchDB\CouchDBClient::create([‘dbname’ => ‘test_couch’]);

 $client->postDocument([
    "name" => "Lucario",
    "type" => ["Fighting", "Steel"],
    "trainer" => "Korrina",
    "gender" => "f",
    "owned" => "2015-02-13"
]);

Затем мы передаем документ, который мы хотим создать в виде массива. За кулисами это будет преобразовано в строку JSON, которая принимается CouchDB.

 createViewQuery

Чтобы получить документы с использованием определенного представления, мы передаем имя проектного документа и имя представления в качестве аргументов функции setKey Затем мы можем установить ключ с помощью метода execute Чтобы получить ответ, мы вызываем метод $query = $client->createViewQuery('pokemon', 'filter_by_trainer');
$query->setKey('Ash');
$result = $query->execute();
echo "Pokemon trained by Ash: <br>";
foreach($result as $row){
echo $row['value'] . "<br>";
}

 Pokemon trained by Ash: 
Blastoise
Pikachu
Charizard
Talonflame
Froakie

Это даст следующий результат:

 setGroup

Если вы добавили функцию сокращения в представление, вы должны вызвать метод truesetGroup Установка truetrainer

 $query = $client->createViewQuery('pokemon', 'group_by_trainer');
$query->setReduce('true');
$query->setGroup('true');
$result = $query->execute();
foreach($result as $row){
    echo $row['key'] . "<br>";
    echo "Pokemon count: " . $row['value'] . "<br>";
    echo "<br>";
}

Это даст нам следующий результат:

 Ash
Pokemon count: 5

Brock
Pokemon count: 1

Elesa
Pokemon count: 1

Erika
Pokemon count: 1

Korrina
Pokemon count: 1

Misty
Pokemon count: 3

Ramos
Pokemon count: 1

Team Rocket
Pokemon count: 1

Чтобы обновить документ, сначала мы должны найти его самую последнюю версию. Это связано с тем, что клиент CouchDB не предоставляет функциональности, которая позволяет нам просто передавать поля, которые мы хотим обновить. CouchDB — это база данных только для добавления, поэтому нам всегда нужно получить текущую версию документа, обновить или добавить нужные нам поля, а затем выполнить фактическое обновление.

 $doc_id = '5a6a50b7c98499a4d8d69d4bfc003c9c';
$doc = $client->findDocument($doc_id);

$updated_doc = $doc->body;
$updated_doc['name'] = 'Golduck';
$updated_doc['owned'] = '1999-07-29';

$client->putDocument($updated_doc, $doc->body['_id'], $doc->body['_rev']);

Как и при обновлении документа, нам нужно выполнить запрос GET Затем мы вызываем функцию deleteDocument

 $doc_id = '7c7f800ee10a39f512a456339e0027fe';
$doc = $client->findDocument($doc_id);
$client->deleteDocument($doc_id, $doc->body['_rev']);

Вывод

CouchDB — это очень удобная и простая в использовании база данных документов с акцентом на производительность и контроль версий.

Теперь вы научились работать с ним и выполнять различные операции с базой данных с помощью Postman и двух клиентов PHP. Если вы хотите узнать больше, я рекомендую вам ознакомиться с Подробным руководством, которое содержит все, что вам нужно знать о CouchDB. В следующем посте мы пойдем гораздо глубже и создадим правильное мультиплатформенное приложение, используя все, что мы видели до сих пор.

До тех пор, как их лозунг говорит — расслабься!