Лабораторная работа №2. Подготовка данных исследование, очистка
Скачать 0.54 Mb.
|
Лабораторная работа №2 Тема: Подготовка данных: исследование, очистка. Цель работы: Сформировать у студентов навыки создания БД в MongoDB со стандартными операциями работы с данными. План работы: Установка и администрирование базы данных Работа с данными Работа с данными в MongoDB Compass Установка и администрирование базы данных Рассмотрим базовые операции с данными в MongoDB с примением консольной оболочки mongo, и графического клиента MongoDB Compass. Однако в любом случае при начале работы с сервером следует не забывать запускать сам сервер - то есть приложение mongod. Начиная работать с MongoDB в консольной оболочке mongo, первым делом надо установить нужную нам базу данных в качестве текущей, чтобы затем ее использовать. Для этого надо использовать команду use, после которой идет название базы данных. При этом не важно, существует ли такая бд или нет. Если ее нет, то MongoDB автоматически создаст ее при добавлении в нее данных. Итак, запустим консольную оболочку mongo.exe и введем там следующую команду: Теперь в качестве текущей будет установлена БД test. Если вы вдруг не уверены, а существует ли уже база данных с таким названием, то с помощью команды show dbs можно вывести названия всех имеющихся бд на консоль: Для базы данных можно задать любое имя, однако есть некоторые ограничения. Например, в имени не должно быть символов /, \, ., ", *, <, >, :, |, ?, $. Кроме того, имена баз данных ограничены 64 байтами. Также есть зарезервированные имена, которые нельзя использовать: local, admin, config. Эти имена представляют базы данных, которые уже имеют по умолчанию на сервере и предназначны для служебных целей. Причем как вы видите, бд test в данном списке нет, так как я в нее еще не добавил данные. Если мы хотим узнать, какая бд используется в текущей момент, то мы можем воспользоваться командой db: Кроме баз данных мы можем просмотреть список всех коллекций в текущей бд с помощью команды show collections. Получение статистикиИспользуя команду db.stats(), можно получить статистику по текущей базе данных. Например, у нас в качестве текущей установлена база данных test: Похожим образом мы можем узнать всю статистику по отдельной коллекции. Например, узнаем статистику по коллекции users: db.users.stats() Работа с данными Добавление данных Установив бд, теперь мы можем добавить в нее данные. Все данные хранятся в бд в формате BSON, который близок к JSON, поэтому нам надо также вводить данные в этом формате. И хотя у нас, возможно, на данный момент нет ни одной коллекции, но при добавлении в нее данных она автоматически создается. Как ранее говорилось, имя коллекции - произвольный идентификатор, состоящий из не более чем 128 различных алфавитно-цифровых символов и знака подчеркивания. В то же время имя коллекции не должно начинаться с префикса system., так как он зарезервирован для внутренних коллекций (например, коллекция system.users содержит всех пользователей базы данных). И также имя не должно содержать знака доллара - $. Для добавления в коллекцию могут использоваться три ее метода: insertOne(): добавляет один документ insertMany(): добавляет несколько документов insert(): может добавлять как один, так и несколько документов Итак, добавим один документ:
Документ представляет набор пар ключ-значение. В данном случае добавляемый документ имеет три ключа: name, age, languages, и каждому из них сопоставляет определенное значение. Например, ключу languages в качесте значения сопоставляется массив. Некоторые ограничения при использовании имен ключей: Символ $ не может быть первым символом в имени ключа Имя ключа не может содержать символ точки . При добавлении данных, если мы явным образом не предоставили значение для поля "_id" (то есть уникального идентификатора документа), то оно генерируется автоматически. Но в принципе мы можем сами установить этот идентификатор при добавлении данных:
Стоит отметить, что названия ключей могут использоваться в кавычках, а могут и без кавычек. В случае удачного добавления на консоль будет выведен идентификатор добавленного документа. И чтобы убедиться, что документ в бд, мы его выводим функцией find.
По умолчанию он выводит все документы коллекции: Чтобы вывести в более читабельном виде добавим метод pretty():
Если надо добавить ряд документов, то мы можем воспользоваться методом insertMany():
После добавления консоль выводит идентификаторы добавленных документов: Есть еще один способ добавления в бд документа, который включает два этапа: определение документа (document = ( { ... } )) и собственно его добавление:
Возможно, не всем будет удобно вводить в одну строчку все пары ключей и свойств. Но интеллектуальный интерпретатор MongoDB на основе javascript позволяет также вводить и многострочные команды. Если выражение не закончено (с точки зрения языка JavaScript), и вы нажимаете Enter, то ввод следующей части выражения автоматически переносится на следующую строку: Загрузка данных из файлаДанные для базы данных mongodb можно определять в обычном текстовом файле, что довольно удобно, поскольку мы можем переносить или пересылать этот файл независимо от базы данных mongodb. Например, определим где-нибудь на жестком диске файл users.js со следующим содержимым:
То есть здесь с помощью метода insertMany добавляются три документа в коллекцию users. Для загузки файла в текущую базу данных применяется функция load(), в которую в качестве параметра передается путь к файлу:
В данном случае предполагается, что файл располагается по пути "D:/users.js". Выборка из БД Наиболее простой способом получения содержимого БД представляет использование функции find. Действие этой функции во многом аналогично обычному запросу SELECT * FROM Table, который применяется в SQL и который извлекает все строки. Например, чтобы извлечь все документы из коллекции users, созданной в прошлой теме, мы можем использовать команду db.users.find(). Для вывода документов в более удобном наглядном представлении мы можем добавить вызов метода pretty():
Функция find() позволяет возвратить несколько документов. Еще одна функция findOne() работает похожим образом, только возвращает один документ:
Фильтрация данныхОднако что, если нам надо получить не все документы, а только те, которые удовлетворяют определенному требованию. Например, мы ранее в базу добавили следующие документы:
Выведем все документы, в которых name=Tom:
Такой запрос выведет нам два документа, в которых name=Tom. Теперь более сложный запрос: нам надо вывести те объекты, у которых name=Tom и одновременно age=32. То есть на языке SQL это могло бы выглядеть так: SELECT * FROM Table WHERE Name='Tom' AND Age=32. Данному критерию у нас соответствует последний добавленный объект. Тогда мы можем написать следующий запрос:
Фильтрация по отсутствующим свойствамКакие-то документы могут иметь определенное свойство, другие могут его не иметь. Что если мы хотим получить документы, в которых отсутствует определенное свойство? В этом случае для свойства передается значение null. Например, найдем все документы, где отсутствует свойство languages:
Или найдем все документы, где name="Tom", но свойство languages не определено.
Фильтрация по элементам массиваТакже несложно отыскать по элементу в массиве. Например, следующий запрос выводит все документы, у которых в массиве languages есть english:
Усложним запрос и получим те документы, у которых в массиве languages одновременно два языка: "english" и "german":
Причем именно в этом порядке, где "english" определен первым, а "german" - вторым. Теперь выведем все документы, в которых "english" в массиве languages находится на первом месте:
Обратите внимание, что "languages.0" предоставляет сложное свойство и поэтому берется в кавычки. Соответственно если нам надо вывести документы, где english на втором месте (например, ["german", "english"]), то вместо нуля ставим единицу: "languages.1". ПроекцияДокумент может иметь множество полей, но не все эти поля нам могут быть нужны и важны при запросе. И в этом случае мы можем включить в выборку только нужные поля, использовав проекцию. Например, выведем только порцию информации, например, значения полей "age" у все документов, в которых name=Tom:
Использование единицы в качестве параметра {age: 1} указывает, что запрос должен вернуть только содержание свойства age. И обратная ситуация: мы хотим найти все поля документа кроме свойства age. В этом случае в качестве параметра указываем 0:
При этом надо учитывать, что даже если мы отметим, что мы хотим получить только поле name, поле _id также будет включено в результирующую выборку. Поэтому, если мы не хотим видеть данное поле в выборке, то надо явным образом указать: {"_id":0} Альтернативно вместо 1 и 0 можно использовать true и false:
Если мы не хотим при этом конкретизировать выборку, а хотим вывести все документы, то можно оставить первые фигурные скобки пустыми:
Запрос к вложенным объектамПредыдущие запросы применялись к простым объектам. Но документы могут быть очень сложными по структуре. Например, добавим в коллекцию users следующий документ:
Здесь определяется вложенный объект с ключом company. И чтобы найти все документы, у которых в ключе company вложенное свойство name=microsoft, нам надо использовать оператор точку:
Использование JavaScriptMongoDB предоставляет замечательную возможность, создавать запросы, используя язык JavaScript. Например, создадим запрос, возвращающий те документы, в которых name=Tom. Для этого сначала объявляется функция:
Собственно только запросами область применения JavaScript в консоли mongo не ограничена. Например, мы можем создать какую-нибудь функцию и применять ее:
Использование регулярных выраженийЕще одной замечательной возможностью при построении запросов является использование регулярных выражений. Например, найдем все документы, в которых значение ключа name начинается с буквы B: > db.users.find({name:/^B\w+/i}) Настройка запросов и сортировкаMongoDB представляет ряд функций, которые помогают управлять выборкой из бд. Одна из них - функция limit. Она задает максимально допустимое количество получаемых документов. Количество передается в виде числового параметра. Например, ограничим выборку тремя документами:
В данном случае мы получим первые три документа (если в коллекции 3 и больше документов). Но что, если мы хотим произвести выборку не сначала, а пропустив какое-то количество документов? В этом нам поможет функция skip. Например, пропустим первые три записи:
MongoDB предоствляет возможности отсортировать полученный из бд набор данных с помощью функции sort. Передавая в эту функцию значения 1 или -1, мы можем указать в каком порядке сортировать: по возрастанию (1) или по убыванию (-1). Во многом эта функция по действию аналогична выражению ORDER BY в SQL. Например, сортировка по возрастанию по полю name:
Ну и в конце надо отметить, что мы можем совмещать все эти функции в одной цепочке:
Поиск одиночного документаЕсли все документы извлекаются функцией find, то одиночный документ извлекается функцией findOne. Ее действие аналогично тому, как если бы мы использовали функцию limit(1), которая также извлекает первый документ коллекции. А комбинация функций skip и limit извлечет документ по нужному местоположению. Параметр $naturalЕсли вдруг нам надо отсортировать ограниченную коллекцию, то мы можем воспользоваться параметром $natural. Этот параметр позволяет задать сортировку: документы передаются в том порядке, в каком они были добавлены в коллекцию, либо в обратном порядке. Например, отберем последние пять документов:
Оператор $slice$slice является в некотором роде комбинацией функций limit и skip. Но в отличие от них $slice может работать с массивами. Оператор $slice принимает два параметра. Первый параметр указывает на общее количество возвращаемых документов. Второй параметр необязательный, но если он используется, тогда первый параметр указывает на смещение относительно начала (как функция skip), а второй - на ограничение количества извлекаемых документов. Например, в каждом документе определен массив languages для хранения языков, на которых говорит человек. Их может быть и 1, и 2, и 3 и более. И допустим, ранее мы добавили следующий объект:
И мы хотим при выводе документов сделать так, чтобы в выборку попадал только один язык из массива languages, а не весь массив:
Данный запрос при извлечении документа оставит в результате только первый язык из массива languages, то есть в данном случае english. Обратная ситуация: нам надо оставить в массиве также один элемент, но не с начала, а с конца. В этом случае необходимо передать в параметр отрицательное значение:
Теперь в массиве окажется german, так как он первый с конца в добавленном элементе. Используем сразу два параметра:
Первый параметр говорит начать выборку элементов с конца (так как отрицательное значение), а второй параметр указывает на количество возвращаемых элементов массива. В итоге в массиве language окажется "german" КурсорыРезультат выборки, получаемой с помощью функции find, называется курсором:
Курсоры инкапсулируют в себе наборы получаемых из бд объектов. Используя синтаксис языка javascript и методы курсоров, мы можем вывести полученные документы на экран и как-то их обработать. Например:
Курсор обладает методом hasNext, который показывает при переборе, имеется ли еще в наборе документ. А метод next извлекает текущий документ и перемещает курсор к следующему документу в наборе. В итоге в переменной obj оказывается документ, к полям которого мы можем получить доступ. Также для перебора документов в курсоре в качестве альтернативы мы можем использовать конструкцию итератора javascript - forEach:
Чтобы ограничить размер выборки, используется метод limit, принимающий количество документов:
Стоит обратить внимание, что, чтобы сразу же не выводить все содержащиеся в курсоре данные, после метода limit() через точку с запятой добавляется выражение null; Используя метод sort(), можно отсортировать документы в курсоре:
Выражение cursor.sort({name:1}) сортирует документы в курсоре по полю name по возрастанию. Если мы хотим отсортировать по убыванию, то вместо 1 используем -1: cursor.sort({name:-1}) И еще один метод skip() позволяет пропустить при выборке определенное количество документов:
В данном случае пропускаем два документа. И кроме того, можно объединять все эти методы в цепочки:
Команды группировки: count, distinct. Число элементов в коллекцииС помощью функции count() можно получить число элементов в коллекции:
Можно группировать параметры поиска и функцию count, чтобы подсчитать, сколько определенных документов, например, у которых name=Tom:
Более того мы можем создавать цепочки функций, чтобы конкретизировать условия подсчета:
Здесь надо отметить, что по умолчанию функция count не используется с функциями limit и skip. Чтобы их использовать, как в примере выше, в функцию count надо передать булевое значение true Функция distinctВ коллекции могут быть документы, которые содержат одинаковые значения для одного или нескольких полей. Например, в нескольких документах определено name: "Tom". И нам надо найти только уникальные различающиеся значения для одного из полей документа. Для этого мы можем воспользоваться функцией distinct:
Здесь запрашиваются только уникальные значения для поля name. И на следующей строке консоль выводит в виде массива найденные уникальные значения. Операторы выбора Условные операторыУсловные операторы задают условие, которому должно соответствовать значение поля документа: $eq (равно) $ne (не равно) $gt (больше чем) $lt (меньше чем) $gte (больше или равно) $lte (меньше или равно) $in определяет массив значений, одно из которых должно иметь поле документа $nin определяет массив значений, которые не должно иметь поле документа Например, найдем все документы, у которых значение ключа age меньше 30:
Аналогично будет использование других операторов сравнения. Например, тот же ключ, только больше 30:
Обратите внимание, что сравнение здесь проводится над целочисленными типами, а не строками. Если ключ age представляет строковые значения, то соответственно надо проводить сравнение над строками: db.users.find ({age: {$gt : "30"}}), однако результат будет тем же. Но представим ситуацию, когда нам надо найти все объкты со значением поля age больше 30, но меньше 50. В этом случае мы можем комбинировать два оператора:
Найдем пользователей, возраст которых равен 22:
По сути это аналогия следующего запроса:
Обратная операция - найдем пользователей, возраст которых НЕ равен 22:
Оператор $in определяет массив возможных выражений и ищет те ключи, значение которых имеется в массиве:
Противоположным образом действует оператор $nin - он определяет массив возможных выражений и ищет те ключи, значение которых отсутствует в этом массиве:
Логические операторыЛогические операторы выполняются над условиями выборки: $or: соединяет два условия, и документ должен соответствовать одному из этих условий $and: соединяет два условия, и документ должен соответствовать обоим условиям $not: документ должен НЕ соответствовать условию $nor: соединяет два условия, и документ должен НЕ соответстовать обоим условиям Оператор $orОператор $or представляет логическую операцию ИЛИ и определяет набор пар ключ-значение, которые должны иметься в документе. И если документ имеет хоть одну такую пару ключ-значение, то он соответствует данному запросу и извлекается из бд:
Это выражение вернет нам все документы, в которых либо name=Tom, либо age=22. Другой пример вернет нам все документы, в которых name=Tom, а age равно либо 22, либо среди значений languages есть "german":
В подвыраженях or можно применять условные операторы:
В данном случае мы выбираем все документы, где name="Tom" или поле age имеет значение от 30 и выше. Оператор $andОператор $and представляет логическую операцию И (логическое умножение) и определяет набор критериев, которым обязателньо должен соответствовать документ. В отличие от оператора $or документ должен соответствовать всем указанным критериям. Например:
Здесь выбираемые документы обязательно должны имееть имя Tom и возраст 32 - оба этих признака. Поиск по массивамРяд операторов предназначены для работы с массивами: $all: определяет набор значений, которые должны иметься в массиве $size: определяет количество элементов, которые должны быть в массиве $elemMatch: определяет условие, которым должны соответствовать элемены в массиве $allОператор $all определяет массив возможных выражений и требует, чтобы документы имели весь определяемый набор выражений. Соответственно он применяется для поиску по массиву. Например, в документах есть массив languages, хранящий иностранные языки, на которых говорит пользователь. И чтобы найти всех людей, говорящих одновременно и по-английски, и по-французски, мы можем использовать следующее выражение:
Оператор $elemMatchОператор $elemMatch позволяет выбрать документы, в которых массивы содержат элементы, попадающие под определенные условия. Например, пусть в базе данных будет коллекция, которая содержит оценки пользователей по определенным курсам. Добавим несколько документов:
Каждый документ имеет массив courses, который в свою очередь состоит из вложенных документов. Теперь найдем студентов, которые для курса MongoDB имеют оценку выше 3:
Оператор $sizeОператор $size используется для нахождения документов, в которых массивы имеют число элементов, равным значению $size. Например, извлечем все документы, в которых в массиве laguages два элемента:
Такой запрос будет соответствовать, например, следующему документу:
Оператор $existsОператор $exists позволяет извлечь только те документы, в которых определенный ключ присутствует или отсутствует. Например, вернем все документы, в который есть ключ company:
Если мы укажем у оператора $exists в качестве параметра false, то запрос вернет нам только те документы, в которых не определен ключ company. Оператор $typeОператор $type извлекает только те документы, в которых определенный ключ имеет значение определенного типа, например, строку или число:
Оператор $regexОператор $regex задает регулярное выражение, которому должно соответствовать значение поля. Например, пусть поле name обязательно имеет букву "b":
Важно понимать, что $regex принимает не просто строки, а именно регулярные выражения, например: name: {$regex:"om$"} - значение name должно оканчиваться на "om". Работа с данными в MongoDB Compass Для базовых операций, как то: создание/удаление коллекций, добавление, просмотр, изменения и удаления документов есть соответствующие элементы графического интерфейса: При выборе определенной коллекции и отображении ее данных над список данных есть кнопка для добавления данных, в том числе для импорта из внешнего файла. А напротив каждого документа есть опции для его просмотра, изменения и удаления: Но несмотря на наличие графических возможностей для управления данными, они могут оказаться недостаточными для каких-то более сложных сценариев работы с данными. И для этого в MongoDB Compass есть встроенный консольный клиент Mongosh, в котором можно вводить почти все те же команды для работы с данными, что и в консольной оболочке mongo: Но также стоит отметить, что консольный клиент в Compass несколько упрощает написание запросов. Прежде всего, можно копировать и вставлять запросы в mongosh. Также mongosh имеет функцию автодополнения, которая позволяет нам предложить варианты доступых функций: Кроме того, как видно на скриншоте выше, mongosh позволяет нас уведомить об устаревших функциях. Так, выше на скриншоте применялась устаревшая функция insert() для добвления в базу данных документа. Хотя mongosh выполнил данную функцию, тем не менее сопроводил ее выполнение соответствующими сообщениями. А в консольной оболочке mongo выполнение подобной функции прошло бы без каких-либо проблем. Задание лабораторной работы Изучить теоретический материал Установить администрирование базы данных Выполнить операции для работа с данными Отличить работу с данными в MongoDB Compass от работы в консоле. |