Это вторая статья, посвященная графовой базе данных Neo4j. Первую статью о моделировании схемы данных можно почитать тут: https://habr.com/ru/post/677296/ Суть статьи — небольшое практическое отступление до того, как мы разберем новые концепции в Neo4j. Все приведенные в статье примеры будут работать, если скачать и поставить себе по ссылке локально бесплатную копию Neo4j с предустановленной Movie DBMS. Разберем простейший синтаксис написания запросов к Neo4j по CRUD. Для начала, надо вспомнить что в структуре данных у нас есть: Nodes — сущности; Labels — метки к сущностям; Relationships — однонаправленные отношения между сущностями; Properties — свойства сущностей или отношений. Очень упрощенно, основной шаблон запроса для чтения записей можно описать следующим образом: Согласен, с примером будет понятнее :) Вспомним нашу базу данных с фильмами и актерами, и попробуем сделать запрос к ней Для получения какой-то выборки используется ключевое слово MATCH (точная копия SELECT из RDBMS). m:Movie — тут мы присваиваем переменной m все найденные Movies по заданным условиям. RETURN p — явно указываем что должен вернуть наш запрос. Больше примеров: {name: 'Tom Hanks'} — условие фильтрации по сущности Person Но, графовая БД не была бы таковой, если бы в ней не было главной особенности: связей между сущностями. Давайте найдем все фильмы, в которых играл Tom Hanks: m — тут мы присваиваем переменной m все найденные зависимые сущности по заданным условиям. Отлично! Но неправильно :) Потому что это вернет нам все его связи со всеми зависимыми сущностями по всей базе данных, если таковые будут. Нам это не нужно, мы хотим получить фильмы, в которых он играл. Добавим тип связи ACTED_IN: Уже лучше, но тоже неточно. Этот запрос вернет все сущности, в которых он играл, не только фильмы. Он же мог играть и в театральных постановках, правильно? Эти примеры выше работают благодаря так называемомой способности traverse, если говорить в терминах Neo4j. Нода, хоть как-то связанная с другой нодой (даже через другие N нод), соответственно, — traversable-нода. Конкретно в нашей схеме данных других сущностей нет, поэтому получим только Movies. Но лучше не копить техдолг, а явно указать что мы ожидаем только фильмы: Теперь отлично! Больше примеров: Можно комбинировать связи: В общем случае, ключевое слово WHERE работает почти так-же, как и в RDBMS, поэтому на нем подробно останавливаться не буду. Однако есть интересные применения в контексте проверки связей: Для добавления данных в Neo4j используется слово MERGE, однако будет большой ошибкой проводить полную аналогию с ключевыми словами CREATE или INSERT из RDBMS. Дело в том, что MERGE создает паттерн в базе данных.  Проще сразу с примерами: Небольшое отступление: можно также использовать ключевое слово CREATE с той лишь разницей, что CREATE не будет проверять по первичному ключу существует ли уже такая нода в БД — это дает ему огромное преимущество в скорости. CREATE чаще всего используют для дампов, чтобы быстро можно было их развернуть на чистой базе. MERGE занимается вставкой данных более аккуратно — с проверкой всех условий, но и более медленно. Создадим простой паттерн через MERGE: Ничего не изменилось. Дело в том, что в этом запросе MATCH говорит нам о том, что мы должны найти записи, а MERGE о том, что мы должны создать связь между ними. Однако, если записи не найдены, то связь и не создастся. Для гарантированного создания сущности или связи можно использовать MERGE для всех трех частей запроса: Что тут происходит по логике обработчика запроса: Neo4j пытается найти сущность Person с именем Michael Cain; Если сущность найдена, то Neo4j смотрит все ее связи ACTED_IN; Затем среди этих связей Neo4j ищет Movie с названием The Dark Knight. Если хотя-бы на одном из этих этапов не было найдено объектов, то будет создан весь паттерн. То есть, если даже фильм The Dark Knight существует, а актер Michael Cain нет,  то будет создан новый фильм с таким названием. Это важнейшая особенность, которую стоит учитывать, чтобы избегать дублирования данных. Попробуем воспроизвести это: Решением такого кейса может быть создание всех сущностей отдельно и затем отдельно связей между ними. Всё отдельными запросами. Более сложный пример для создания паттернов: Также полезно знать, что для добавления и обновления атрибутов используется ключевое слово SET: Это, пожалуй, самый простой раздел, потому что ломать — не строить :) Самое важное знание тут — это то, что нельзя удалить ноду, пока у нее есть хоть одна связь. Удалим все фильмы с названием The Diamond Arm, которые мы создали ранее: Окей, нельзя удалять пока есть связи. Для быстрой починки этого у нас есть ключевая пара слов DETACH DELETE. Но если мы используем такое для удаления фильмов, то никогда потом не найдем актеров из них, которых тоже хотелось бы удалить. Тогда удалим сначала актеров, потом сами дубликаты фильмов: Для удаления атрибутов можно просто присвоить им значение null или явно вызвать ключевое слово REMOVE: Как видно из примеров выше, работать с графовыми БД довольно просто, но в то же время необычно для тех, кто много времени проводит с SQL, нужно немного перестроить мышление. А о том, как это сделать я расскажу в следующих статьях ;-)  CTO