Изучаем MongoDB: запросы к Документам — 2

Spread the love

Перевод: ParasLearn MongoDB: Query Documents — II

Продолжим прошлую статью о работе с документами. В предыдущем посте я рассмотрел простые запросы и запросы к встроенным документам с помощью нескольких типов операторов, доступных в mongodb. В этом посте рассмотрим операторы, связанные с массивами и оценкой данных.


Содержание:

  • Операторы оценочного запроса
  • Запросы к массивам
  • Операторы массивов

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

Вместо одной weakness теперь мы будем сохранять для покемонов набор weaknesses.

{
   name: "pikachu",
   type: "Electric",
   stats: {
     health: 40,
     attack: 50,
     defense: 45
   },
   level: 16,
   weakness: ["ground", "grass", "dragon"], // now it's array
   evolution: "raichu",
   moves: [
      {name: "quick attack", dmg: 40},
      {name: "thunder bolt", dmg: 90},
      {name: "irontail", dmg: 50}
   ]   
}

Операторы оценочного запроса

Об операторах оценочного запроса сказать особо нечего. Они просто проводят оценку.

  • $regex (позволяет указать выражение регулярного выражения в вашем запросе)
  • $text (полезно при работе с индексами в mongodb, поэтому сейчас не рассматривается)
  • $jsonSchema (Для проверки данных по схеме)
  • $expr
  • $mod ( { field: { $mod: [ divisor, remainder ] } })

Использование:

# $regex находит покемонов с "pi" в их именах
> db.persons.find({ description: {$regex: /pi/}})

# создать валидатор при создании коллекции
# давайте создадим простую схему для коллекции покемонов
> db.createCollection( <collection>, { validator: { 
    required: ["name", "type", "level"],
   $jsonSchema: {
      name: { bsonType: "string" },
      type: { bsonType: "string" },
      level: { bsonType: "int", minimum: 1 }
   }
}})

# $mod помогают выполнять операцию модификации поля с числом
# получаем всех покемонов, чей уровень делится на 5
> db.pokemons.find({level: {$mod: [5, 0]}}) # divisor, remainder

$expr : Этот оператор помогает использовать выражения агрегирования в запросе.

  • Сравнение полей: вы можете использовать оператор $expr для сравнения двух полей. Например. мы можем сравнить уровень и поле защиты в нашей коллекции покемонов
# получить всех покемонов, у которых level превышает их defense
> db.pokemons.find({$expr: {$gt: ["$level", "$stats.defense"] }})

Есть еще один оператор $cond, который помогает нам создавать условия (if, then, else). Мы рассмотрим его позже в этой серии.

Запросы к массивам

Теперь мы узнаем, как работать с массивами внутри документов.

Простой запрос элемента в массиве : Вы можете запрашивать массивы в обычном режиме, а обо всем остальном позаботится mongo. Он проверит, существует ли значение в массиве или нет.

# найти всех покемонов с weakness "ground"
> db.pokemons.find({weakness: "ground"})

# если вы сделаете что-то подобное, он проверит точное совпадение массива
> db.pokemons.find({weakness: ["ground"]})

Запрос по индексу в массиве : Можно запросить элемент по конкретному индексу в массиве. Просто укажите индекс, аналогично указанию ключа в объекте.

> db.pokemons.find({"weakness.2": "electric" })

Что, если у нас есть встроенные документы внутри массива ?? (Подсказка: аналогично встроенным документам)

# найти всех покемонов, у которых есть "quick attack"
> db.pokemons.find({"moves.name": "quick attack"})

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

// e.g collection = articles
{
   comments: [
      { name: "Nina", rating: 3 },
      { name: "Colt", rating: 4 },
      { name: "Rico", rating: 2.5}
   ]
}
# допустим нам нужно найти статьи, в которых рейтинг больше 2 

# это не сработает, так как будет поиск на точное совпадение
> db.articles.find({"comments": { name: "Nina", rating: {$gt: 2}}})

# это тоже не сработает
# имя может совпасть с другим комментарием, чем рейтинг
> db.articles.find({"comments.name": "Nina", "comments.rating": {$gt: 2}})

Эта проблема решается с помощью операторов.

Операторы массивов

Операторов у массивов немного, но они очень полезны.

  • Operators: $all$size$elemMatch

$all : Рассмотрим его на примере. Допустим нам надо найдите всех покемонов, чьи weakness имеет значение ground и electric.

> db.pokemons.find({weakness: {$all: ["ground", "electric"]}})

# Не пытайтесь выполнить следующий запрос, потому что
# будет искать точное совпадение
> db.pokemons.find({weakness: ["ground", "electric"]})

$all проверяет, находится ли все элементы в массиве. Это могут быть объекты, отдельные значения или массивы. Он также игнорирует порядок, в котором вы указали элементы в запросе.

$size : Запрос на размер массива

# найти всех покемонов с 4 ходами
> db.pokemons.find({moves: {$size: 4}})

Оператор $size принимает только точное число. Запросы больше или меньше невозможны.

$elemMatch : Очень нужный оператор!!! … Шучу. Вы помните пример, который мы использовали при запросе встроенных документов в массиве? $elemMatch может нам в этом помочь !! Посмотрим как

// e.g collection = articles
{
   comments: [
      { name: "Nina", rating: 3 },
      { name: "Colt", rating: 4 },
      { name: "Rico", rating: 2.5}
   ]
}
# найти все статьи, в рейтинг Nina имеет значение больше 2
> db.articles.find({
   comments: {
      $elemMatch: {name: "Nina", rating: {$gt: 2}}
   }
})

Что только что произошло в этом запросе ??

$elemMatch помог нам определить, как должен выглядеть документ, который может соответствовать нашему запросу. Круто, не правда ли?

Заключение

Итак, мы все рассмотрели для запросов к массивам и встроенным документам. Если у вас есть вопросы, не стесняйтесь задавать их в комментариях (в блоге автора статьи). Я постараюсь ответить на них.

Была ли вам полезна эта статья?
[2 / 3]

Spread the love
Подписаться
Уведомление о
guest
0 Комментарий
Oldest
Newest Most Voted
Inline Feedbacks
View all comments