Синтаксис запросов MongoDB

Автор: | 10.09.2014

СУБД MongoDB относится к NoSQL базам данных, основной чертой которых является нереляционный характер и соответственно язык запросов, отличный от SQL. В MongoDB в качестве язык запросов используется JavaScript и JSON-структуры. Выбор столь нехарактерного языка запроса объясняется тем, что эта документ-ориентированная СУБД использует JSON-формат для представления документов и вывода результатов. Физически JSON-структуры хранятся в бинарном BSON-формате.

Вставка нового документа

Внутри текущей базы данных создаются коллекции, вставка нового документа в коллекцию при помощи метода insert приводит к её автоматическому созданию. В качестве аргумента, метод insert принимает JSON-объект, который служит телом документа. Ниже в базу данных вставляются документы с единственным ключом title, в качестве значения которого выступают названия различных СУБД.

db.mybase.insert({title: "MySQL"})
db.mybase.insert({title: "PostreSQL"})
db.mybase.insert({title: "MongoDB"})
db.mybase.insert([{title: "MS SQL"}, {title: "Oracle"}])


Формат JSON допускает создание как единичных объектов, так и массивов. Записи «MySQL», «PostreSQL» и «MongoDB» вставляются отдельными вставками, в то время как «MS SQL» и «Oracle» при помощи массива, элементы которого в JSON заключаются в квадратные скобки. Для каждого документа автоматически создается идентификатор «_id», который можно задавать вручную, с единственным условием, чтобы он оставался уникальным в рамках текущей базы данных. Идентификатор, который формируется по умолчанию, формируется по следующему алгоритму: в старших четырех байтах находится время создания записи в формате UNIXSTAMP, следующие три байта — идентификатор компьютера, следующие два — идентификатор процесса, последние три — локальный счетчик процесса.

Основная особенность MongoDB заключается в том, что документ или запись может быть настолько сложной по структуре, насколько допускает формат JSON. В качестве примера, в отдельной базе данных articles создадим набор статей, имеющий название и набор ключевых слов

db.articles.insert({title: "Обзор NoSQL решений", tags: ["NoSQL", "MongoDB", "memcached", "CouchDB", "Riak", "HBase", "Redis"]})
db.articles.insert({title: "MongoDB", tags: ["NoSQL", "MongoDB"]})
db.articles.insert({title: "Redis", tags: ["NoSQL", "Redis"]})

 

Здесь помимо поля title, создается поле tags, представляющего собой массив ключевых слов. Элементы массивов и значения могут сами быть составными JSON-объектами и массивами. В результате одна запись в базе данных может представлять собой сложную структуру и значительно отличаться по своему составу от соседней (в отличие от традиционных реляционных баз данных, в которых структура записей в таблице строгая).

 

Типы данных

 

MongoDB поддерживает следующие типы данных:

  • string — строки должны быть представлены в кодировке UTF-8;
  • числа
    • double — 8-байтные числа с плавающей точкой IEEE;
    • int — 4-байтное целое число;
    • long — 8-байтное целое число;
  • datetime — календарный тип для хранения даты и времени, представляющий собой 8-байтное целое число, хранящее количество миллисекунд прошедших с 1 января 1970 года;

При вставке чисел через JavaScript следует иметь в виду, что JavaScript поддерживает только числовой тип Number, соответствующий типу double. Поэтому для явной вставки целых чисел типа int и long следует использовать классы NumberInt() и NumberLong(), соответственно.

db.numbers.save({num: NumberLong(5)});


Извлечение результатов

 

Для подсчета количества документов в текущей базе данных можно воспользоваться методом count()

db.mybase.count()
5

Для того, чтобы извлечь результаты можно воспользоваться методом find()

db.mybase.find()
{ "_id" : ObjectId("51eb8c2bb4d7d4d898b05fce"), "title" : "MySQL" }
{ "_id" : ObjectId("51eb905ab4d7d4d898b05fcf"), "title" : "PostreSQL" }
{ "_id" : ObjectId("51eb9061b4d7d4d898b05fd0"), "title" : "MongoDB" }
{ "_id" : ObjectId("51eb907db4d7d4d898b05fd1"), "title" : "MS SQL" }
{ "_id" : ObjectId("51eb907db4d7d4d898b05fd2"), "title" : "Oracle" }

Методы, допускают использование селекторов, например, для извлечения документа, соответствующего MySQL методу find() можно передать следующий JSON-объект

db.mybase.find({"title" : "MySQL"})
{ "_id" : ObjectId("51eb9bb1303d105141c7d74b"), "title" : "MySQL" }

Аналогично можно подсчитать количество статей с названием "MySQL", передав методу count селектор "title" : "MySQL"

db.mybase.count({"title" : "MySQL"})
1
 

Объекты и переменные JavaScript

Консоль mongo позволяет не только задействовать предопределенные объекты, но и вводить свои. Ниже вводится JavaScript-объект where, в котором формируется условие поиска, далее в метод find() может передаваться объект.

var where = {}
where['title'] = "MySQL"
db.mybase.find(where)
{ "_id" : ObjectId("51eba53f303d105141c7d751"), "title" : "MySQL" }

Консоль поддерживает и более сложные приемы JavaScript-программирования, например, создание собственных методов.

 

Регулярные выражения

В качестве селектора могут выступать не только строки, но и регулярные выражения, например, для извлечения всех записей поле title, которые начинаются с символа M можно воспользоваться регулярным выражением /^M/ передав его методу find()

db.mybase.find({title: /^M/});
{ "_id" : ObjectId("51f4dae823d2a4ef32d25ec4"), "title" : "MySQL" }
{ "_id" : ObjectId("51f4dae823d2a4ef32d25ec6"), "title" : "MongoDB" }
{ "_id" : ObjectId("51f4dae923d2a4ef32d25ec7"), "title" : "MS SQL" }
 

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

Для сортировки результатов используется метод sort(), который принимает в качестве параметров JSON-структуру, ключом в которой выступает название сортируемого поля, а в качестве значения выступает целое число: положительное — прямая сортировка, отрицательная — обратная

db.mybase.find({title: /^M/}).sort({title: 1});
{ "_id" : ObjectId("51f53e56a631742542dda011"), "title" : "MS SQL" }
{ "_id" : ObjectId("51f53e55a631742542dda010"), "title" : "MongoDB" }
{ "_id" : ObjectId("51f53e55a631742542dda00e"), "title" : "MySQL" }
db.mybase.find({title: /^M/}).sort({title: -1});
{ "_id" : ObjectId("51f53e55a631742542dda00e"), "title" : "MySQL" }
{ "_id" : ObjectId("51f53e55a631742542dda010"), "title" : "MongoDB" }
{ "_id" : ObjectId("51f53e56a631742542dda011"), "title" : "MS SQL" }

Сортировать можно по нескольким полям одновременно. Создадим таблицу с двумя полями fst и snd

db.sortexmpl.insert({fst: 2, snd: 5})
db.sortexmpl.insert({fst: 1, snd: 12})
db.sortexmpl.insert({fst: 2, snd: 2})
db.sortexmpl.insert({fst: 1, snd: 20})
db.sortexmpl.insert({fst: 2, snd: 7})
db.sortexmpl.insert({fst: 1, snd: 6})

Ниже приводится пример сортировки по двум полям одновременно

db.sortexmpl.find()
{ "_id" : ObjectId("51f56e07a631742542dda016"), "fst" : 2, "snd" : 5 }
{ "_id" : ObjectId("51f56e07a631742542dda017"), "fst" : 1, "snd" : 12 }
{ "_id" : ObjectId("51f56e07a631742542dda018"), "fst" : 2, "snd" : 2 }
{ "_id" : ObjectId("51f56e07a631742542dda019"), "fst" : 1, "snd" : 20 }
{ "_id" : ObjectId("51f56e07a631742542dda01a"), "fst" : 2, "snd" : 7 }
{ "_id" : ObjectId("51f56e07a631742542dda01b"), "fst" : 1, "snd" : 6 }
db.sortexmpl.find().sort({fst: 1, snd: 1})
{ "_id" : ObjectId("51f56e07a631742542dda01b"), "fst" : 1, "snd" : 6 }
{ "_id" : ObjectId("51f56e07a631742542dda017"), "fst" : 1, "snd" : 12 }
{ "_id" : ObjectId("51f56e07a631742542dda019"), "fst" : 1, "snd" : 20 }
{ "_id" : ObjectId("51f56e07a631742542dda018"), "fst" : 2, "snd" : 2 }
{ "_id" : ObjectId("51f56e07a631742542dda016"), "fst" : 2, "snd" : 5 }
{ "_id" : ObjectId("51f56e07a631742542dda01a"), "fst" : 2, "snd" : 7 }

Ограничение выборки по полям документа

По умолчанию выборка содержит все поля документа, однако, в том случае, если требуется выбрать лишь конкретные поля, методам find() и findOne() можно передавать второй аргумент в виде JSON-структуры, с ключами, совпадающими с названиями столбцов и значениями 1, если поле должно попадать в выборку и 0, если его необходимо исключить из выборки. В следующем запросе извлекаются только названия title, идентификатор _id исключается из выборки:

db.mybase.find({title: /^M/}, {title: 1, _id: 0}).sort({title: 1});
{ "title" : "MS SQL" }
{ "title" : "MongoDB" }
{ "title" : "MySQL" }

Более того, не обязательно указывать включаемые поля, достаточно перечислить поля, которые не должны попасть в выборку

db.mybase.find({title: /^M/}, {_id: 0}).sort({title: 1});
{ "title" : "MS SQL" }
{ "title" : "MongoDB" }
{ "title" : "MySQL" }

Если в условии нет необходимости, то в качестве первого запроса метода find() передается пустой селектор

db.mybase.find({}, {_id: 0}).sort({title: 1});
{ "title" : "MS SQL" }
{ "title" : "MongoDB" }
{ "title" : "MySQL" }
{ "title" : "Oracle" }
{ "title" : "PostreSQL" }
 

Ограничение выборки по количеству документов

Для того, чтобы извлечь лишь одно значение из полученной выборки можно воспользоваться методом findOne()

db.mybase.findOne({title: /^M/});
{ "_id" : ObjectId("51f4dae823d2a4ef32d25ec4"), "title" : "MySQL" }

Однако, к методу findOne() прибегают чаще в тех ситуациях, когда ожидается, что результирующая коллекция будет содержать лишь один документ. В тех же случаях, когда следует ограничить выборку несколькими документами предпочитают использовать метод limit(), который принимает в качестве аргумента количество извлекаемых документов. Следующий запрос вернут только 2 статьи из коллекции mybase

db.mybase.find({title: /^M/}).sort({title: 1}).limit(2);
{ "_id" : ObjectId("51f53e56a631742542dda011"), "title" : "MS SQL" }
{ "_id" : ObjectId("51f53e55a631742542dda010"), "title" : "MongoDB" }

Для организации постраничной навигации может потребоваться метод skip(), который позволяет в пропустить в выборке количество аргументов, указанных в его параметре. Так, чтобы извлечь содержимое следующей «страницы»:

db.mybase.find({title: /^M/}).sort({title: 1}).skip(0).limit(2);
{ "_id" : ObjectId("51f53e56a631742542dda011"), "title" : "MS SQL" }
{ "_id" : ObjectId("51f53e55a631742542dda010"), "title" : "MongoDB" }
db.mybase.find({title: /^M/}).sort({title: 1}).skip(2).limit(2);
{ "_id" : ObjectId("51f53e55a631742542dda00e"), "title" : "MySQL" }

При использовании больших значений в качестве параметра метода skip() следует помнить, методу приходится пропускать это значение записей, прежде чем добраться до извлекаемых. В этом случае разумно отказаться от skip() и использовать операторы сравнения.

Условная выборка

Создадим коллекцию lang, содержащую документы состоящие из двух полей, title — название базы данных и query — используемый ей язык запросов

db.lang.insert({title: "MySQL", query: "SQL"})
db.lang.insert({title: "PostgreSQL", query: "SQL"})
db.lang.insert({title: "MongoDB", query: "JavaScript"})

Как уже упоминалось ранее для выбора условия, необходимо передавать JSON-структуру методам find(), findOne(), count() и т.д. Следующий метод извлекает все базы данных, начинающиеся с символа M

db.lang.find({title: /^M/})
{ "_id" : ObjectId("51f55285a631742542dda013"), "title" : "MySQL", "query" : "SQL" }
{ "_id" : ObjectId("51f55286a631742542dda015"), "title" : "MongoDB", "query" : "JavaScript" }


Логические операторы

JSON-структура в методе find(), может содержать несколько полей, при этом условия объединяются по логике AND (И). В следующем примере выбираются базы данных начинающиеся с символа M, и использующие JavaScript в качестве языка запросов.

db.lang.find({query: "JavaScript", title: /^M/})
{ "_id" : ObjectId("51f55286a631742542dda015"), "title" : "MongoDB", "query" : "JavaScript" }

Для формирования логики OR (ИЛИ) предназначен оператор $or, который оперирует массивом аргументов, так запрос извлекающий записи, или начинающиеся со символа M, или использующие в качестве языка запроса SQL может выглядеть следующим образом

db.lang.find({$or: [{query: "SQL"}, {title: /^M/}]})
{ "_id" : ObjectId("51f55285a631742542dda013"), "title" : "MySQL", "query" : "SQL" }
{ "_id" : ObjectId("51f55285a631742542dda014"), "title" : "PostgreSQL", "query" : "SQL" }
{ "_id" : ObjectId("51f55286a631742542dda015"), "title" : "MongoDB", "query" : "JavaScript" }

В таблице ниже представлены логические операторы сравнения и логические операторы MongoDB

 
Оператор SQL MongoDB Описание
< $lt меньше
<= $lte меньше или равно
> $gt больше
>= $gte больше или равно
<> $ne не равно
NOT $not отрицание
EXISTS $exists проверка существования поля
OR $or или
NOT OR $nor не или
RLIKE, REGEXP $regex соответствие регулярному выражению
LIKE $elemMatch соответствие всех полей вложенного документа
$size соответствие размеру массива
$type соответствие, если поле имеет указанный тип

Операторы из таблицы выше можно использовать как по отдельности, так и в комбинации

db.lang.find({_id: {$gt: ObjectId("51f55285a631742542dda013")}})
{ "_id" : ObjectId("51f55285a631742542dda014"), "title" : "PostgreSQL", "query" : "SQL" }
{ "_id" : ObjectId("51f55286a631742542dda015"), "title" : "MongoDB", "query" : "JavaScript" }
db.lang.find({_id: {$lt: ObjectId("51f55285a631742542dda015")}})
{ "_id" : ObjectId("51f55285a631742542dda013"), "title" : "MySQL", "query" : "SQL" }
{ "_id" : ObjectId("51f55285a631742542dda014"), "title" : "PostgreSQL", "query" : "SQL" }
db.lang.find({_id: {$gt: ObjectId("51f55285a631742542dda013"), $lt: ObjectId("51f55285a631742542dda015")}})
{ "_id" : ObjectId("51f55285a631742542dda014"), "title" : "PostgreSQL", "query" : "SQL" }

В оболочке mongo можно составлять более сложные программы. Так например, двойное условие из предыдущего примера можно оформить в виде объекта, подставляемого в JSON-структуру

var conditions = {}
conditions['$gt'] = ObjectId("51f55285a631742542dda013")
ObjectId("51f88c41b49ab634fd78bf93")
conditions['$lt'] = ObjectId("51f55285a631742542dda015")
ObjectId("51f88c41b49ab634fd78bf95")
db.lang.find(conditions)
db.lang.find({_id: conditions})
{ "_id" : ObjectId("51f55285a631742542dda014"), "title" : "PostgreSQL", "query" : "SQL" }


Работа со списками

Для работы со списками предназначены операторы $in, $nin и $all.

 
Оператор SQL MongoDB Описание
IN $in входит в список
NOT IN $nin не входит в список
ALL $all одновременное совпадение набора элементов

Оператор $in извлекает записи для которых заданное значение совпадает хотя бы с одним из списка. Ниже выводится запрос, извлекающий записи, поле title которых совпадает с одним из значений в списке ['MongoDB', 'MySQL']:

db.lang.find({title: {$in: ['MongoDB', 'MySQL']}})
{ "_id" : ObjectId("51f55285a631742542dda013"), "title" : "MySQL", "query" : "SQL" }
{ "_id" : ObjectId("51f55286a631742542dda015"), "title" : "MongoDB", "query" : "JavaScript" }

Для извлечения всех записей, не входящих в список ['MongoDB', 'MySQL'] можно воспользоваться оператором $nin

db.lang.find({title: {$nin: ['MongoDB', 'MySQL']}})
{ "_id" : ObjectId("51f88c41b49ab634fd78bf94"), "title" : "PostgreSQL", "query" : "SQL" }


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

 

Для обновления используется метод update, первый аргумент которого определяет список обновляемых документов, второй — как отобранные документы модифицируются. Следующая команда добавляет в документ с названием "MongoDB" дополнительное поле nosql, со значением "true":

db.mybase.update({"title": "MongoDB"}, {$set: {nosql: "true"}})
db.mybase.find()
{ "_id" : ObjectId("51eb9bb1303d105141c7d74b"), "title" : "MySQL" }
{ "_id" : ObjectId("51eb9bb1303d105141c7d74c"), "title" : "PostreSQL" }
{ "_id" : ObjectId("51eb9bb2303d105141c7d74e"), "title" : "MS SQL" }
{ "_id" : ObjectId("51eb9bb2303d105141c7d74f"), "title" : "Oracle" }
{ "_id" : ObjectId("51eb9bb1303d105141c7d74d"), "nosql" : "true", "title" : "MongoDB" }

Если обновлению подвергается только одно поле, следует обязательно использовать оператор $set. Если его опустить, вместо обновления поля, будет обновлен весь документ:

db.mybase.update({"title": "MongoDB"}, {nosql: "true"})
db.mybase.find()
{ "_id" : ObjectId("51eba53f303d105141c7d751"), "title" : "MySQL" }
{ "_id" : ObjectId("51eba53f303d105141c7d752"), "title" : "PostreSQL" }
{ "_id" : ObjectId("51eba53f303d105141c7d754"), "title" : "MS SQL" }
{ "_id" : ObjectId("51eba53f303d105141c7d755"), "title" : "Oracle" }
{ "_id" : ObjectId("51f9582829b045085952815f"), "nosql" : "true" }

Для удаления дополнительного поля nosql, вместо оператора $set, следует подставить $unset

> db.mybase.update({"title": "MongoDB"}, {$unset: {nosql: "none"}})
> db.mybase.find({"title": "MongoDB"})
{ "_id" : ObjectId("51eb9bb1303d105141c7d74d"), "title" : "MongoDB" }

Для того, чтобы добавить ключевое слово в массив тэгов tags базы данных articles следует воспользоваться оператором $addToSet

db.articles.update({tags: "Redis"}, {$addToSet: {tags: "Обзор"}})

Если запросить состав текущей базы данных при помощи метода find(), можно заметить, что обновился только один документ из двух, которые имеют ключевое слово "Redis". Для того, чтобы обновить все документы, следует передать четвертому параметру метода update() значение true, что заставит MongoDB обновить все найденные документы

db.articles.update({tags: "Redis"}, {$addToSet: {tags: "Обзор"}}, false, true)

Ниже приводится сводная таблица по операторам, используемым совместно с методом update()

 
Оператор Описание
$set обновление или создание поля
$unset удаление поля
$inc увеличение значения поля на заданное число
$pop удаляет последний (или первый) элемент массива
$pushAll помещает несколько элементов в массив
$push помещает новый элемент в массив
$addToSet помещает новый элемент в массив (исключаются дубликаты)
$pull удаляет из массива значение (при его наличии)
$pullAll удаляет из массива все подходящие значения

 

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

Полностью удалить документы из текущей базы данных можно при помощи метода remove()

db.mybase.remove()

Точно также, как и другие методы, в качестве параметра метод может принимать селекторы, например, удалить все записи в ключом nosql равным "true" можно при помощи следующей команды

db.mybase.remove({nosql: "true"})

Ссылки

Взято отсюда — http://softtime.info

Добавить комментарий

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