9 типов операторов MongoDB, которые вам нужно знать

Опубликовано: 2022-09-09

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

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

Эта статья прольет свет на операторы, используемые в программном обеспечении базы данных MongoDB.

Что такое операторы MongoDB?

MongoDB — это программное обеспечение базы данных NoSQL, которое управляет информацией, ориентированной на документы.

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

Операторы — это специальные символы, которые помогают компиляторам выполнять математические или логические задачи. MongoDB предлагает несколько типов операторов для взаимодействия с базой данных.

Типы операторов MongoDB

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

К концу статьи вы сможете изучить основы каждого оператора и его функций.

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

Логические операторы часто используются для фильтрации данных на основе заданных условий. Они также позволяют оценивать многие условия, которые мы обсудим более подробно.

Ниже приведены несколько логических операторов, которые вы можете использовать:

Условие «и» выполняет логическую операцию «и» над массивом из двух или более выражений. Он выбирает документы, в которых выполняются все условия выражений.

Это стандартный синтаксис выражения $and :

 { $and: [ { <expression1> }, { <expression2> }, ... , { <expressionN> } ] } Например, если мы хотим выбрать документы, цена которых составляет 10 долларов США, а количество меньше 15, мы можем ввести следующий запрос:
 db.inventory.find( { $and: [ { quantity: { $lt: 15 } }, { price: 10 } ] } )

$ или

Условие «ИЛИ» выполняет логическую операцию «ИЛИ» над массивом из двух или более выражений. Он выбирает документы, в которых хотя бы одно из выражений верно.

Это стандартный синтаксис для выражения $or :

 { $or: [ { <expression1> }, { <expression2> }, ... , { <expressionN> } ] }.

Например, если мы хотим выбрать документы, цена которых составляет 10 долларов США или количество которых меньше 15, мы можем ввести следующий запрос:

 db.inventory.find( { $or: [ { quantity: { $lt: 15 } }, { price: 10 } ] } )

Нам не нужно ограничивать выражение двумя критериями — мы можем добавить больше. Например, приведенный ниже запрос выбирает те документы, где цена равна 10 долларам, количество меньше 15 или тег неизменен:

 db.inventory.find( { $or: [ { quantity: { $lt: 15 } }, { price: 10 }, { tag: stationary }] } )

При выполнении этих предложений MongoDB либо выполняет сканирование коллекции, либо сканирование индекса. Если все индексы поддерживают предложения, MongoDB использует индексы для проверки выражения $or . В противном случае вместо этого используется сканирование коллекции.

Но если вы хотите проверить критерии в том же поле, вы можете использовать оператор $in , а не оператор $or . Например, если вам нужна коллекция документов, количество которых равно 10 или 20, вместо этого вам может потребоваться выполнить приведенный ниже запрос $in :

 db.inventory.find ( { quantity: { $in: [20, 50] } } )

Подробнее об операторе $in мы поговорим позже.

$нор

Этот оператор выполняет логическую операцию «ни» над массивом, используя одно или несколько выражений. Затем он выбирает документы, которые не удовлетворяют выражениям запроса. Проще говоря, это действие противоположно условию $or .

Это общий синтаксис:

 { $nor: [ { <expression1> }, { <expression2> }, ... { <expressionN> } ] }

Рассмотрим следующий запрос:

 db.inventory.find( { $nor: [ { price: 3.99 }, { sale: true } ] } )

Этот запрос выбирает документы, которые содержат:

  • значение поля цены не равно $3,99, а значение продажи не равно true; или же
  • значение поля цены не равно $3,99, а также пустое или отсутствующее поле продажи; или же
  • нет поля цены, а поле продажи не равно true; или же
  • ни поле цены, ни поле продажи не заполнены и не представлены.

$не

Этот оператор выполняет логическую операцию «не» над массивом для указанного выражения. Затем он выбирает документы, которые не соответствуют выражениям запроса. Сюда входят документы, не содержащие поля.

Это общий синтаксис:

 { field: { $not: { <operator-expression> } } }

Например, возьмем следующий запрос:

 db.inventory.find( { price: { $not: { $lt: 3.99 } } } )

Этот запрос выберет те документы, которые содержат:

  • поле цены, значение которого больше или равно 3,99 доллара США; а также
  • поле цены не заполнено или не существует.

Операторы сравнения

Операторы сравнения можно использовать для сравнения значений в одном или нескольких документах.

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

 { _id: 1, item: { name: "apple", code: "123" }, qty: 15, tags: [ "A", "B", "C" ] }, { _id: 2, item: { name: "banana", code: "123" }, qty: 20, tags: [ "B" ] }, { _id: 3, item: { name: "spinach", code: "456" }, qty: 25, tags: [ "A", "B" ] }, { _id: 4, item: { name: "lentils", code: "456" }, qty: 30, tags: [ "B", "A" ] }, { _id: 5, item: { name: "pears", code: "000" }, qty: 20, tags: [ [ "A", "B" ], "C" ] }, { _id: 6, item: { name: "strawberry", code: "123" }, tags: [ "B" ] }

Далее мы будем использовать этот пример при подробном описании каждого оператора сравнения.

Равно ($ экв.)

Этот оператор сопоставляет значения, которые равны заданному значению:

 { <field>: { $eq: <value> } }

Например, если мы хотим получить определенный документ из коллекции инвентаризации, имеющий точное значение количества «20», мы должны ввести следующую команду:

 db.inventory.find( { qty: { $eq: 20 } } )

Запрос вернет следующее:

 { _id: 2, item: { name: "banana", code: "123" }, qty: 20, tags: [ "B" ] }, { _id: 5, item: { name: "pears", code: "000" }, qty: 20, tags: [ [ "A", "B" ], "C" ] }

Больше, чем ($ gt)

Этот оператор соответствует, если значения больше заданного значения:

 { field: { $gt: value } }

В этом примере мы извлекаем документы, количество которых превышает 15:

 db.inventory.find({"qty": { $gt: 15}})

Запрос вернет следующее:

 { _id: 2, item: { name: "banana", code: "123" }, qty: 20, tags: [ "B" ] } { _id: 3, item: { name: "spinach", code: "456" }, qty: 25, tags: [ "A", "B" ] } { _id: 4, item: { name: "lentils", code: "456" }, qty: 30, tags: [ "B", "A" ] } { _id: 5, item: { name: "pears", code: "000" }, qty: 20, tags: [ [ "A", "B" ], "C" ] }

Менее ($ lt)

Этот оператор соответствует, если значения меньше предоставленного значения:

 { field: { $lt: value } }

Найдем документы с количеством меньше 25:

 db.inventory.find({"qty": { $lt: 25}})

Запрос вернет следующее:

 { _id: 1, item: { name: "apple", code: "123" }, qty: 15, tags: [ "A", "B", "C" ] } { _id: 2, item: { name: "banana", code: "123" }, qty: 20, tags: [ "B" ] } { _id: 5, item: { name: "pears", code: "000" }, qty: 20, tags: [ [ "A", "B" ], "C" ] }

Больше или равно ($gte)

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

 { field: { $gte: value } }

В этом примере мы извлекаем документы, количество которых больше или равно 25:

 db.inventory.find({"qty": { $gte: 25}})

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

 { _id: 3, item: { name: "spinach", code: "456" }, qty: 25, tags: [ "A", "B" ] } { _id: 4, item: { name: "lentils", code: "456" }, qty: 30, tags: [ "B", "A" ] }

Меньше или равно ($lte)

Этот оператор соответствует, только если значения меньше или равны заданному значению:

 { field: { $lte: value } }

Найдем документы с количеством меньше или равным 25.

 db.inventory.find({"qty": { $lte: 25}})

Мы можем ожидать, что этот запрос вернет следующее:

 { _id: 1, item: { name: "apple", code: "123" }, qty: 15, tags: [ "A", "B", "C" ] } { _id: 2, item: { name: "banana", code: "123" }, qty: 20, tags: [ "B" ] } { _id: 3, item: { name: "spinach", code: "456" }, qty: 25, tags: [ "A", "B" ] } { _id: 5, item: { name: "pears", code: "000" }, qty: 20, tags: [ [ "A", "B" ], "C" ] }

В ($ в)

Этот оператор возвращает документы, соответствующие указанным значениям:

 { field: { $in: [<value1>, <value2>, ... <valueN> ] } }

Значение поля равно любому значению в указанном массиве. Например, чтобы получить документы со значениями «30» и «15» в коллекции инвентаризации, вы должны сделать следующее:

 db.collection.find({ "qty": { $in: [30, 15]}})

Результат будет:

 { _id: 1, item: { name: "apple", code: "123" }, qty: 15, tags: [ "A", "B", "C" ] } { _id: 4, item: { name: "lentils", code: "456" }, qty: 30, tags: [ "B", "A" ] }
Запрос выполняется в оболочке MongoDB.

Нет в ($ нин)

Этот оператор возвращает документы, которые не соответствуют заданным значениям. Вот основной синтаксис оператора $nin :

 { field: { $nin: [ <value1>, <value2> ... <valueN> ]

$nin выбирает документы, в которых:

  • значение поля не входит в указанный массив; или же
  • поле не существует.

Если поле содержит массивы, оно выберет массивы, в которых отсутствует элемент, указанный в разделе значений. Например, мы хотим выбрать те документы, в которых количество не равно ни 20, ни 15.

Кроме того, он также соответствует документам, у которых нет поля количества:

 db.collection.find({ "qty": { $nin: [ 20, 15 ]}}, {_id: 0})

Результат будет:

 { _id: 3, item: { name: "spinach", code: "456" }, qty: 25, tags: [ "A", "B" ] } { _id: 4, item: { name: "lentils", code: "456" }, qty: 30, tags: [ "B", "A" ] } { _id: 6, item: { name: "strawberry", code: "123" }, tags: [ "B" ] }

Не равно ($ne)

Оператор $ne возвращает документы, в которых указанное значение не равно:

 { $ne: value } }

Например, предположим, что мы хотим выбрать все документы, количество которых не равно 20:

 db.inventory.find( { qty: { $ne: 20 } } )

Результат будет:

 { _id: 1, item: { name: "apple", code: "123" }, qty: 15, tags: [ "A", "B", "C" ] } { _id: 3, item: { name: "spinach", code: "456" }, qty: 25, tags: [ "A", "B" ] } { _id: 4, item: { name: "lentils", code: "456" }, qty: 30, tags: [ "B", "A" ] } { _id: 6, item: { name: "strawberry", code: "123" }, tags: [ "B" ] }

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

Операторы элемента

Операторы запроса элемента могут идентифицировать документы, используя поля документа. Операторы элементов состоят из $exist и $type .

$ существует

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

Если указано значение true , оно соответствует документам, содержащим это поле, включая документы, в которых значение поля равно null. Если <boolean> имеет значение false , запрос возвращает только те документы, которые не содержат поля.

Вот стандартный синтаксис:

 { field: { $exists: <boolean> } }

Давайте возьмем пример, где у нас есть данные коллекции для массива с именем «bagofmarbles», где каждый мешок содержит шарики разных цветов:

 { red: 5, green: 5, blue: null } { red: 3, green: null, blue: 8 } { red: null, green: 3, blue: 9 } { red: 1, green: 2, blue: 3 } { red: 2, blue: 5 } { red: 3, green: 2 } { red: 4 } { green: 2, blue: 4 } { green: 2 } { blue: 6 }

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

 db.bagofmarbles.find( { red: { $exists: true } } )

Результаты будут состоять из тех документов, которые содержат поле «красный», даже если значение равно null . Однако он не будет состоять из документов, в которых поле «красный» даже не существует:

 { red: 5, green: 5, blue: null } { red: 3, green: null, blue: 8 } { red: null, green: 3, blue: 9 } { red: 1, green: 2, blue: 3 } { red: 2, blue: 5 } { red: 3, green: 2 } { red: 4 }

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

 db.bagofmarbles.find( { red: { $exists: false} }

Результаты будут состоять из тех документов, которые не содержат поле «красный»:

 { green: 2, blue: 4 } { green: 2 } { blue: 6 }

$тип

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

Это общий синтаксис для $type :

 { field: { $type: <BSON type> } }

Допустим, у нас есть адресная книга, содержащая следующие документы:

 db={ addressBook: [ { "_id": 1, address: "2100 Jupiter Spot", zipCode: "9036325" }, { "_id": 2, address: "25 Moon Place", zipCode: 26237 }, { "_id": 3, address: "2324 Neptune Ring", zipCode: NumberLong(77622222) }, { "_id": 4, address: "33 Saturns Moon", zipCode: NumberInt(117) }, { "_id": 5, address: "1044 Venus Lane", zipCode: [ "99883637232", "73488976234" ] } ] }

При рассмотрении вышеуказанных документов почтовый индекс имеет разные типы данных. Сюда входят длинные, двойные, целые и строковые значения.

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

 db.addressBook.find({ "zipCode": { $type: "string" } })

Это вернет следующие документы:

 [ { "_id": 1, "address": "2100 Jupiter Spot", "zipCode": "9036325" }, { "_id": 5, "address": "1044 Venus Lane", "zipCode": [ "99883637232", "73488976234" ] } ]
Приведенный выше запрос выполняется в оболочке MongoDB.

Кроме того, существует тип «число», который включает все значения типа long, integer или double в виде массива, содержащего элемент указанных типов:

 db.addressBook.find( { "zipCode" : { $type : "number" } } )

Выход:

 [ { "_id": 2, address: "25 Moon Place", zipCode: 26237 }, { "_id": 3, address: "2324 Neptune Ring", zipCode: NumberLong(77622222) }, { "_id": 4, address: "33 Saturns Moon", zipCode: NumberInt(117) } ]

Если документы имеют тип поля массива, оператор $type возвращает документы, в которых хотя бы один элемент массива соответствует типу, переданному оператору.

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

MongoDB также состоит из операторов массивов для запроса документов, содержащих массивы.

Есть три основных оператора: $all , $elemMatch и $size . Ниже мы подробно обсудим каждый из них.

$ все

Оператор $all выбирает документы, в которых значением поля является массив, содержащий указанные элементы:

 { : { $all: [ <value1> , <value2> ... ] } }

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

 { _id: ObjectId("5234cc89687ea597eabee675"), code: "shirt", tags: [ "sale", "shirt", "button", "y2k", "casual" ], qty: [ { size: "S", num: 10, color: "blue" }, { size: "M", num: 45, color: "blue" }, { size: "L", num: 100, color: "green" } ] }, { _id: ObjectId("5234cc8a687ea597eabee676"), code: "pant", tags: [ "y2k", "trendy", "shine" ], qty: [ { size: "6", num: 100, color: "green" }, { size: "6", num: 50, color: "blue" }, { size: "8", num: 100, color: "brown" } ] }, { _id: ObjectId("5234ccb7687ea597eabee677"), code: "pant2", tags: [ "trendy", "shine" ], qty: [ { size: "S", num: 10, color: "blue" }, { size: "M", num: 100, color: "blue" }, { size: "L", num: 100, color: "green" } ] }, { _id: ObjectId("52350353b2eff1353b349de9"), code: "shirt2", tags: [ "y2k", "trendy" ], qty: [ { size: "M", num: 100, color: "green" } ] }

Мы хотели бы получить любые документы (в данном случае одежду) из инвентаря, которые связаны с тегами «модный» и «2k». В приведенном ниже запросе используется оператор $all , где значением поля tags является массив, элементы которого включают «y2k» и «mode»:

 db.inventory.find( { tags: { $all: [ "y2k", "trendy" ] } } )

Приведенный выше запрос возвращает следующее:

 { _id: ObjectId("5234cc8a687ea597eabee676"), code: "pant", tags: [ "y2k", "trendy", "shine" ], qty: [ { size: "6", num: 100, color: "green" }, { size: "6", num: 50, color: "blue" }, { size: "8", num: 100, color: "brown" } ] } { _id: ObjectId("52350353b2eff1353b349de9"), code: "shirt2", tags: [ "y2k", "trendy" ], qty: [ { size: "M", num: 100, color: "green" } ] }
Приведенный выше запрос выполняется в оболочке MongoDB.

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

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

 db.collection.find({ $and: [ { tags: "y2k" }, { tags: "trendy" } ] })
Приведенный выше запрос выполняется в оболочке MongoDB.

$elemMatch

Оператор $elemMatch сопоставляет документы, содержащие поле массива, хотя бы с одним элементом, соответствующим всем указанным критериям запроса:

 { : { $elemMatch: { <query1>, <query2>, ... } } }

Хотя мы можем использовать операторы сравнения, такие как $lte и $gte , если мы указываем только одно условие запроса внутри $elemMatch и не используем операторы $not или $ne , использование $elemMatch можно опустить, поскольку оно по существу будет выполнять та же самая функция.

Есть еще несколько вещей, о которых следует помнить при использовании этого оператора, в основном:

  • Вы не можете указать выражение $where where в операции $elemMatch .
  • Вы не можете указать выражение запроса $ $text в операции $elemMatch .

Например, у нас есть следующие документы в коллекции результатов учащихся:

 { _id: 1, results: [ 92, 89, 98 ] } { _id: 2, results: [ 85, 99, 99 ] }

Следующий запрос соответствует только тем документам, в которых массив результатов содержит хотя бы один элемент, который больше или равен 90 и меньше 95:

 db.studentresults.find( { results: { $elemMatch: { $gte: 90, $lt: 95 } } })

Наш запрос возвращает следующий документ, поскольку элемент 92 одновременно больше или равен 90 и меньше 95:

 { "_id" : 1, "results" :[ 92, 89, 98 ] }

$ размер

Оператор $size возвращает те документы, в которых размер массива соответствует количеству элементов, указанному в аргументе:

 { field: { $size: value } }

Вот пример:

 db.collection.find( { field: { $size: 2 } });

Это вернет все документы в указанной коллекции, где поле представляет собой массив с двумя элементами: { field: [ orange, apple] } и { field: [ blue, red] } , но не { field: blue} или { field: [ raspberry, lemon, grapefruit ] } .

Однако, хотя мы можем ввести конкретное значение в качестве размера, мы не можем указать диапазоны значений в качестве размера.

Геопространственные операторы

MongoDB позволяет хранить геопространственные данные в виде типов GeoJSON. GeoJSON — это формат открытого стандарта, основанный на нотации объектов JavaScript, который может представлять географические объекты и поддерживать непространственные атрибуты. В этой статье мы поговорим о двух типах геопространственных операторов: спецификаторах геометрии и селекторах запросов.

$геометрия

Этот оператор упоминает геометрию GeoJSON для использования со следующими операторами геопространственных запросов: $geoIntersects , $geoWithin , $nearSphere и $near . $geometry использует EPSG:4326 в качестве системы координат по умолчанию (CRS).

Чтобы упомянуть объекты GeoJSON с CRS по умолчанию, вы можете использовать следующий фрагмент для $geometry :

 $geometry: { type: "<GeoJSON object type>", coordinates: [ <coordinates> ] }

Чтобы упомянуть многоугольник GeoJSON с одним кольцом и настроенную CRS MongoDB, вы можете использовать следующий фрагмент (вы можете использовать его только для $geoWithin и $geoIntersects ):

 $geometry: { type: "Polygon", coordinates: [ <coordinates> ], crs: { type: "name", properties: { name: "urn:x-mongodb:crs:strictwinding:EPSG:4326" } } }

$полигон

Оператор $polygon можно использовать для указания полигона для геопространственного запроса $geoWithin по устаревшим парам координат. Затем этот запрос вернет пары, попадающие в пределы полигона. Однако $polygon не будет запрашивать какие-либо объекты GeoJSON. Чтобы определить многоугольник, вам нужно указать массив координатных точек следующим образом:

 { : { $geoWithin: { $polygon: [ [ <x1> , <y1> ], [ <x2> , <y2> ], [ <x3> , <y3> ], ... ] } } }

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

Например, следующий запрос вернет все документы, имеющие координаты, существующие в пределах многоугольника, определенного [0,0], [1,5] и [3,3]:

 db.places.find( { loc: { $geoWithin: { $polygon: [ [ 0 , 0 ], [ 1 , 5 ], [ 3 , 3 ] ] } } } )

$geoWithin

Этот оператор можно использовать для выбора документов с геопространственными данными, которые полностью содержатся в определенной форме. Указанная форма может быть мультиполигоном GeoJSON, полигоном GeoJSON (многокольцевым или однокольцевым) или фигурой, которая может быть определена устаревшими парами координат.

Оператор $geoWithin будет использовать оператор $geometry для упоминания объекта GeoJSON.

Чтобы упомянуть мультиполигоны или полигоны GeoJSON через систему координат по умолчанию (CRS), вы можете использовать синтаксис, указанный ниже:

 { : { $geoWithin: { $geometry: { type: <"Polygon" or "MultiPolygon"> , coordinates: [ <coordinates> ] } } } }

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

Чтобы упомянуть полигон GeoJSON с одним кольцом с пользовательской CRS MongoDB, вы можете использовать прототип, упомянутый ниже в выражении $geometry :

 { : { $geoWithin: { $geometry: { type: "Polygon" , coordinates: [ <coordinates> ], crs: { type: "name", properties: { name: "urn:x-mongodb:crs:strictwinding:EPSG:4326" } } } } } }

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

 db.places.find( { loc: { $geoWithin: { $geometry: { type : "Polygon" , coordinates: [ [ [ 0, 0 ], [ 3, 6 ], [ 6, 1 ], [ 0, 0 ] ] ] } } } } )

$ коробка

Вы можете использовать $box чтобы указать прямоугольник для геопространственного запроса $geoWithin , чтобы предоставить документы, которые находятся в пределах прямоугольника, в соответствии с их точечными данными о местоположении. При использовании $geoWithin с $box вы получите документы на основе координат запроса. В этом сценарии $geoWithin не будет запрашивать какие-либо фигуры GeoJSON.

Чтобы использовать оператор $box , вам нужно указать верхний правый и нижний левый углы прямоугольника в объекте массива:

 { <location field> : { $geoWithin: { $box: [ [ <bottom left coordinates> ], [ <upper right coordinates> ] ] } } }

Вышеупомянутый запрос рассчитает расстояние, используя планарную (плоскую) геометрию. Следующий запрос вернет все документы, которые находятся в поле с точками: [0,0], [0,30], [30,0], [30,30]:

 db.places.find ( { loc: { $geoWithin: { $box: [ [ 0,0 ], [ 30,30 ] ] } } } )

$nearSphere

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

MongoDB использует сферическую геометрию для вычисления расстояний для $nearSphere . Ему потребуется геопространственный индекс следующим образом:

  1. 2d индекс для данных о местоположении, описанных как устаревшие пары координат. Чтобы использовать двухмерный индекс для точек GeoJSON, вам необходимо сгенерировать индекс для поля координат объекта GeoJSON.
  2. Индекс 2dsphere для данных о местоположении, описанных как точки GeoJSON.

Чтобы упомянуть точку GeoJSON, вы можете использовать следующий синтаксис:

 { $nearSphere: { $geometry: { type : "Point", coordinates : [ <longitude>, <latitude> ] }, $minDistance: <distance in meters>, $maxDistance: <distance in meters> } }

Здесь $minDistance и $maxDistance необязательны. $minDistance может ограничить результаты теми документами, которые находятся как минимум на указанном расстоянии от центра. Вы можете использовать $maxDistance для любого индекса.

Теперь рассмотрим набор «мест», состоящий из документов с полем местоположения, имеющим индекс 2dsphere. В следующем примере возвращаются точки, расположенные на расстоянии не менее 2000 м и не более 6 000 м от выбранной вами точки, упорядоченные от ближайшей к самой дальней:

 db.places.find( { location: { $nearSphere: { $geometry: { type : "Point", coordinates : [ -43.9532, 50.32 ] }, $minDistance: 2000, $maxDistance: 6000 } } } )

$geoIntersects

Оператор $geoIntersects позволяет выбирать документы, геопространственные данные которых пересекаются с конкретным объектом GeoJSON (т. е. где конвергенция указанного объекта и данных не является пустой). Он использует оператор $geometry для указания объекта GeoJSON.

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

 { <location field>: { $geoIntersects: { $geometry: { type: "<GeoJSON object type>" , coordinates: [ <coordinates> ] } } } }

Следующий экземпляр будет использовать $geoIntersects для выбора всех данных местоположения, которые пересекаются с многоугольником, описанным массивом координат:

 db.places.find( { loc: { $geoIntersects: { $geometry: { type: "Polygon" , coordinates: [ [ [ 0, 0 ], [ 2, 6 ], [ 4, 1 ], [ 0, 0 ] ] ] } } } } )

$ центр

Оператор $center упоминает круг для запроса $geoWithin , который возвращает устаревшие пары координат, находящиеся в пределах круга.

$center не возвращает объекты GeoJSON. Чтобы использовать оператор $center , вам нужно указать массив, который содержит:

  1. Радиус круга, измеренный в единицах, используемых системой координат.
  2. Координаты сетки центральной точки круга.
 { <location field> : { $geoWithin: { $center: [ [ <x> , <y> ] , <radius> ] } } }

Упомянутый ниже пример вернет все документы с координатами, которые можно найти внутри круга с центром в [2,3] и радиусом 40:

 db.places.find( { loc: { $geoWithin: { $center: [ [2, 3], 40 ] } } } )

Операторы проекции

Вы можете использовать операторы проекции, чтобы указать поля, возвращаемые операцией. Операторы проекции MongoDB позволяют использовать функцию find() с аргументами фильтрации данных. Это помогает пользователям извлекать из документа только необходимые поля данных. Таким образом, он позволяет проецировать прозрачные и краткие данные, не влияя на общую производительность базы данных.

$elemMatch (проекция)

Оператор $elemMatch отвечает за ограничение содержимого поля из результатов запроса, чтобы оно содержало только первый элемент, соответствующий $elemMatch .

Вот несколько вещей, о которых вам нужно помнить перед использованием $elemMatch :

  • Начиная с MongoDB 4.4, независимо от порядка полей в документе, проекция $elemMatch существующего поля возвращает поле после включения других существующих полей.
  • Оба оператора $elemMatch и $ отображают первый соответствующий элемент массива на основе заданного условия. Оператор $ будет проецировать первый соответствующий элемент массива из каждого документа в коллекции на основе некоторого условия из оператора запроса, тогда как оператор проецирования $elemMatch принимает явный аргумент условия. Это позволяет проецировать на основе условия, отсутствующего в запросе, или если вам нужно проецировать на основе различных полей во встроенных документах массива.

Вы также должны знать о следующих ограничениях, прежде чем использовать оператор $elemMatch для своих данных:

  • Вы не можете упоминать выражение запроса $text в операторе $elemMatch .
  • db.collection.find() с представлениями не поддерживают оператор проекции $elemMatch .

В следующем примере с оператором проекции $elemMatch предполагается коллекция schools со следующими документами:

 { _id: 1, zipcode: "63108", students: [ { name: "mark", school: 102, age: 9 }, { name: "geoff", school: 101, age: 13 }, { name: "frank", school: 104, age: 12 } ] } { _id: 2, zipcode: "63110", students: [ { name: "harry", school: 103, age: 14 }, { name: "george", school: 103, age: 7 }, ] } { _id: 3, zipcode: "63108", students: [ { name: "harry", school: 103, age: 14 }, { name: "george", school: 103, age: 7 }, ] } { _id: 4, zipcode: "63110", students: [ { name: "jim", school: 103, age: 9 }, { name: "michael", school: 103, age: 12 }, ] }

В этом случае операция find() запрашивает все документы, в которых значение поля почтового индекса равно 63110. Проекция $elemMatch вернет только первый соответствующий элемент массива students , где поле school имеет значение 103:

 db.schools.find( { zipcode: "63110" }, { students: { $elemMatch: { school: 103 } } } ) This is what the result would look like: { "_id" : 2, "students" : [ { "name" : "harry", "school" : 103, "age" : 14 } ] } { "_id" : 4, "students" : [ { "name" : "jim", "school" : 103, "age" : 9 } ] }

$срез (проекция)

Оператор проекции $slice можно использовать для указания количества элементов в массиве, которое будет возвращено в результате запроса:

 db.collection.find( <query> , { <arrayField> : { $slice: <number> } } );

Его также можно выразить так:

 db.collection.find( <query> , { <arrayField> : { $slice: [ <number> , <number> ] } } );

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

 db.posts.insertMany([ { _id: 1, title: "Nuts are not blueberries.", comments: [ { comment: "0. true" }, { comment: "1. blueberries aren't nuts."} ] }, { _id: 2, title: "Coffee please.", comments: [ { comment: "0. Indubitably" }, { comment: "1. Cuppa tea please" }, { comment: "2. frappucino" }, { comment: "3. Mocha latte" }, { comment: "4. whatever" } ] } ])

Следующая операция будет использовать оператор проекции $slice для массива твитов, чтобы вернуть массив с его первыми двумя элементами. Если массив содержит менее двух элементов, возвращаются все элементы массива:

 db.posts.find( {}, { comments: { $slice: 2 } } )

Эта операция вернет следующие документы:

 { "_id" : 1, "title" : "Nuts are not blueberries.", "comments" : [ { "comment" : "0. true" }, { "comment" : "1. blueberries aren't nuts." } ] } { "_id" : 2, "title" : "Coffee please.", "comments" : [ { "comment" : "0. Indubitably" }, { "comment" : "1. Cuppa tea please" } ] }

$ (проекция)

Позиционный оператор $ ограничивает содержимое массива, возвращая первый элемент, соответствующий условию запроса этого массива. Вы можете использовать $ в проекционном документе метода find() или метода findOne() , когда вам требуется только один конкретный элемент массива в выбранных документах.

Вот как выглядит синтаксис оператора $ :

 db.collection.find( { <array>: <condition> ... }, { "<array>.$": 1 } ) db.collection.find( { <array.field>: <condition> ...}, { "<array>.$": 1 } )

В этом примере коллекция students состоит из следующих документов:

 { "_id" : 1, "semester" : 2, "grades" : [ 75, 67, 93 ] } { "_id" : 2, "semester" : 2, "grades" : [ 60, 68, 72 ] } { "_id" : 3, "semester" : 2, "grades" : [ 95, 82, 67 ] } { "_id" : 4, "semester" : 3, "grades" : [ 89, 95, 70 ] } { "_id" : 5, "semester" : 3, "grades" : [ 68, 98, 82 ] } { "_id" : 6, "semester" : 3, "grades" : [ 65, 70, 76 ] }

В следующем запросе проекция { "grades.$": 1 } возвращает только первый элемент, который больше или равен 89 для поля grades :

 db.students.find( { semester: 2, grades: { $gte: 89 } }, { "grades.$": 1 } )

Эта операция возвращает следующие документы:

 {"_id": 3, "grades": [95] }

Операторы оценки

Вы можете использовать операторы оценки MongoDB для оценки общей структуры данных или отдельных полей внутри документа.

Давайте рассмотрим некоторые распространенные операторы оценки MongoDB.

$ мод

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

 { field: { $mod: [ divisor, remainder ] } }

Допустим, у вас есть таблица автомобилей, принадлежащих разным брендам, которые вы владеете в своем автосалоне. Следующий запрос даст вам все марки автомобилей, инвентарные номера которых кратны 250.

 db.cars.find ( { qty: { $mod: [ 250,0 ] } } )

$jsonСхема

$jsonSchema позволяет сопоставлять документы, соответствующие указанной схеме JSON. Реализация схемы JSON в MongoDB включает добавление ключевого слова bsonType , которое позволяет использовать все типы BSON в операторе $jsonSchema .

bsonType может принимать те же псевдонимы строк, которые вы использовали бы для оператора type . Вот как будет выглядеть синтаксис $jsonSchema :

 { $jsonSchema: <JSON Schema object> }

Здесь объект схемы JSON отформатирован на основе проекта 4 стандарта схемы JSON:

 { <keyword1>: <value1>, ... }

Вот пример, демонстрирующий, как работает $jsonSchema :

 { $jsonSchema: { required: [ "name", "major", "gpa", "address" ], properties: { name: { bsonType: "string", description: "must be a string and is required" }, address: { bsonType: "object", required: [ "zipcode" ], properties: { "street": { bsonType: "string" }, "zipcode": { bsonType: "string" } } } } } }

Вы также можете использовать $jsonSchema в средстве проверки документов, чтобы применить указанную схему при операциях обновления и вставки:

 db.createCollection(<collection> , { validator: { $jsonSchema: <schema> } } ) db.runCommand( { collMod: <collection>, validator:{ $jsonSchema: <schema> } } )

Имейте в виду, что есть несколько вещей, которые не поддерживаются оператором $jsonSchema :

  1. Целочисленный тип. Вам нужно использовать тип BSON long или int с ключевым словом bsonType.
  2. Неизвестные ключевые слова.
  3. Связывание свойств и гипермедиа схемы JSON, а также использование ссылок JSON и указателей JSON.

$текст

Оператор $text будет искать текст в содержимом указанного поля, проиндексированного текстовым индексом:

 { $text: { $search: <string>, $language: <string>, $caseSensitive: <boolean>, $diacriticSensitive: <boolean> } }

В этом случае следующий фрагмент кода будет просеивать таблицу, чтобы отфильтровать все автомобили, в которых есть текст «Porsche»:

 db.cars.find( { $text: { $search: "Porsche" } } )

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

Оператор $regex предлагает возможности регулярных выражений для сопоставления строк с образцом в запросах. MongoDB использует регулярные выражения, совместимые с Perl:

 {<field> : /pattern/ <options>}

Следующий пример поможет отфильтровать все автомобили, в которых присутствует строка «$78900»:

 db.cars.find( { price: { $regex: /$78900/ } } )

$выражение

Оператор $expr позволяет использовать выражения агрегации в языке запросов:

 { $expr: { <expression> } }

Вы также можете использовать $expr для создания выражений запроса, которые сравнивают поля из одного и того же документа на этапе $match . Если этап $match является частью этапа $lookup , $expr может сравнивать поля с помощью переменных let.

$где

You can leverage the $where operator to either pass a string containing a full JavaScript function or a JavaScript expression to the query system. The $where operator provides greater flexibility but needs the database to process the JavaScript function or expression for every document in the collection. You can reference this document in the JavaScript function or expression by using either obj or this .

Here's an example of the syntax:

 { $where: <string|JavaScript Code> }

There are a few key considerations to keep in mind before we dive into an example while using the $where operator:

  • You should only use the $where query operator to top-level documents. The $where query operator won't function in a nested document, like in a $elemMatch query.
  • Generally, you should use $where only when you cannot express your query via another operator. If you have to use $where , make sure you include at least one other standard query operator to filter the result set. Using $where independently requires a collection scan for proper execution.

Here's an example to illustrate this:

 db.cars.find( { $where: function() { return (hex_md5(this.name)== "9a43e617b50cd379dca1bc6e2a8") } } );

Bitwise Operators

Bitwise operators return data based on bit position conditions. Simply put, they are used to match numeric or binary values in which any bit from a set of bit positions has a value of 1 or 0.

$bitsAllSet

This operator will match all the documents where all of the bit positions provided by the query are set (ie 1) in the field:

{ <field> : { $bitsAllSet: <numeric bitmask> } }
 { <field> : { $bitsAllSet: < BinData bitmask> } }
 { <field> : { $bitsAllSet: [ <position1> , <position2> , ... ] } }

Значение поля должно быть либо экземпляром BinData, либо числовым для $bitsAllSet , чтобы соответствовать текущему документу.

В следующем примере мы используем коллекцию со следующими документами:

 db.collection.save({ _id: 1, a: 54, binaryValueofA: "00110110" }) db.collection.save({ _id: 2, a: 20, binaryValueofA: "00010100" }) db.collection.save({ _id: 3, a: 20.0, binaryValueofA: "00010100" }) db.collection.save({ _id: 4, a: BinData(0, "Zg=="), binaryValueofA: "01100110" })

Упомянутый ниже запрос будет использовать оператор $bitsAllSet для проверки того, установлены ли в поле a биты в позиции 1 и позиции 5, где младший значащий бит будет в позиции 0:

 db.collection.find( { a: { $bitsAllSet: [ 1, 5 ] } }

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

 { "_id" : 1, "a" : 54, "binaryValueofA" : "00110110" } { "_id" : 4, "a" : BinData(0,"Zg=="), "binaryValueofA" : "01100110" }

$bitsAllClear

Оператор $bitsAllClear будет сопоставлять документы, в которых все битовые позиции, указанные в запросе, пусты или равны 0 :

 { <field> : { $bitsAllClear: <numeric bitmask> } }
 { <field> : { $bitsAllClear: < BinData bitmask> } }
 { <field> : { $bitsAllClear: [ <position1> , <position2> , ... ] } }

Мы будем использовать пример, используемый для $bitsAllSet , чтобы продемонстрировать использование $bitsAllClear . В следующем запросе этот оператор будет использоваться для проверки того, очищены ли биты поля a в позициях 1 и 5:

 db.collection.find( { a: { $bitsAllClear: [ 1, 5 ] } } )

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

 { "_id" : 2, "a" : 20, "binaryValueofA" : "00010100" } { "_id" : 3, "a" : 20, "binaryValueofA" : "00010100" }

Мета-операторы

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

$ подсказка

MongoDB устарела $hint , начиная с версии 3.2. Но этот оператор все еще может быть доступен для драйверов MongoDB, таких как Go, Java, Scala, Ruby, Swift и т. д. Он может заставить оптимизатор запросов использовать определенный индекс для выполнения запроса, который затем может быть упомянут либо в документе, либо в имя индекса.

Вы также можете использовать оператор $hint для проверки стратегий индексирования и производительности запросов. Например, выполните следующую операцию:

 db.users.find().hint( { age: 1 } )

Эта операция вернет все документы в коллекции, называемой users , используя индекс поля age .

Вы также можете упомянуть подсказку, используя одну из следующих форм:

 db.users.find()._addSpecial( "$hint", { age : 1 } ) db.users.find( { $query: {}, $hint: { age : 1 } } )

Если для формы запроса существует индексный фильтр, MongoDB просто проигнорирует $hint .

$комментарий

Оператор $comment позволяет прикрепить комментарий к запросу в любом контексте, в котором может появиться $query . Поскольку комментарии распространяются в журнале профиля, добавление комментария может упростить интерпретацию и отслеживание вашего профиля.

Вы можете использовать $comment одним из трех способов:

 db.collection.find( { <query> } )._addSpecial( "$comment", <comment> ) db.collection.find( { <query> } ).comment( <comment> ) db.collection.find( { $query: { <query> }, $comment: <comment> } )

Если вы хотите прикрепить комментарии к выражениям запроса в других контекстах, например, с db.collection.update() , используйте оператор запроса $comment вместо метаоператора.

$макс.

Вы можете указать значение $max , чтобы указать эксклюзивную верхнюю границу для определенного индекса, чтобы ограничить результаты find() . Этот оператор будет указывать верхнюю границу для всех ключей определенного порядка в индексе.

Mongosh предоставляет вам следующий метод оболочки max() :

 db.collection.find( { <query> } ).max( { field1: <max value> , ... fieldN: <max valueN> } )

Вы также можете указать $max в следующих двух формах:

 db.collection.find( { <query> } )._addSpecial( "$max", { field1: <max value1> , ... fieldN: <max valueN> } ) db.collection.find( { $query: { <query> }, $max: { field1: <max value1> , ... fieldN: <max valueN> } } )

Например, если вы хотите указать эксклюзивную верхнюю границу, имейте в виду следующие операции над именованной коллекцией, которая содержит индекс { age: 1 } :

 db.collection.find( { <query> } ).max( { age: 100 } ).hint( { age: 1 } )

Эта операция ограничит запрос теми документами, в которых возраст поля меньше 100, и вынудит план запроса, который будет сканировать индекс { age: 1 } от minKey до 100.

$объяснить

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

Вы можете указать оператор $explain в любой из следующих форм:

 db.collection.find()._addSpecial( "$explain", 1 ) db.collection.find( { $query: {}, $explain: 1 } )

Лучшие практики для операторов MongoDB

В этом разделе мы рассмотрим некоторые из лучших практик при использовании этих операторов MongoDB.

Встраивание и ссылки

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

Вы можете встраивать данные с отношением 1:1 в один документ. Тем не менее, данные с отношением «многие:1», в которых «многие» объекты появляются вместе с их родительскими документами, также могут быть хорошими кандидатами.

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

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

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

  • Когда вы обновляете сегмент документа, он становится длиннее, а остальная часть документа статична.
  • Когда к документу обращаются, но он содержит редко используемые данные. Встраивание только увеличит требования к памяти, поэтому ссылки имеют больше смысла.
  • Когда размер документа превышает ограничение MongoDB в 16 МБ. Это может произойти при моделировании отношений «много:1» (например, « сотрудники:отдел »).

Изучение шаблонов профилирования и запросов

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

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

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

  • Убедитесь, что у вас есть индексы для любых полей, к которым вы запрашиваете.
  • Сохранение результатов частых подзапросов к документам для снижения нагрузки чтения.
  • Просмотрите свои журналы, чтобы посмотреть на медленные запросы, а затем проверьте свои индексы.

Обзор индексации и моделирования данных

Создавая модель данных, вы будете решать, как моделировать отношения между данными. Например, выбор времени для встраивания документа вместо создания ссылки на отдельные документы в разных коллекциях является примером рассмотрения конкретного приложения.

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

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

  • Геопространственные данные
  • Табличные, плоские и столбчатые структуры
  • Простые пары ключ-значение
  • Данные временного ряда
  • Ребра и узлы структур данных связанного графа и т.п.

Мониторинг шардинга и репликации

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

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

Например, Kinsta APM может собирать информацию с отметками времени о запросах базы данных MySQL вашего сайта WordPress, процессах PHP, внешних HTTP-вызовах и многом другом. Вы также можете использовать этот бесплатный инструмент для отладки:

  • Длинные вызовы API
  • Длинные внешние URL-запросы
  • Медленные запросы к базе данных, и это лишь некоторые из них.

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

Разделенные кластеры в MongoDB — еще один способ потенциального повышения производительности. Подобно репликации, сегментирование можно использовать для распределения больших наборов данных по нескольким серверам.

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

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

Определить использование памяти

MongoDB работает лучше всего, когда рабочий набор приложения (то есть часто используемые данные и индексы) помещается в памяти без проблем. В то время как другие факторы имеют решающее значение для производительности, размер оперативной памяти является наиболее важным для размера экземпляра.

Когда рабочий набор приложения помещается в ОЗУ, активность чтения с диска должна быть низкой. Но если ваш рабочий набор превышает объем оперативной памяти экземпляра сервера или его размер, активность чтения начнет резко возрастать.

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

Разместите поля с несколькими значениями в конце

Если вы индексируете несколько полей, и одно из полей, которое вы хотите запросить, использует один из этих «многозначных» операторов, вы должны поместить их в конец индекса. Вам нужно упорядочить индекс так, чтобы запрашиваемые поля для точных значений были первыми, а «многозначные» операторы отображались последними в индексе.

Исключением будет сортировка по полям. Поместите их между полями «многозначный» и «точный», чтобы сократить объем необходимой сортировки в памяти.

Резюме

Для MongoDB скорость — это название игры. Чтобы быстро возвращать запросы, MongoDB использует операторов для выполнения математических или логических задач. Проще говоря, понимание операторов MongoDB является ключом к освоению MongoDB.

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

Какой из всех операторов вы используете чаще всего и почему? Поделитесь в комментариях ниже — мы будем рады услышать ваше мнение!