Перейти к содержанию

Операторы $where

Пары типа «ключ/значение» являются довольно выразительным способом запроса, но есть запросы, которые они не могут представлять. Для запросов, которые не могут быть выполнены каким-либо другим способом, существуют операторы $where, позволяющие выполнять произвольный код на языке JavaScript как часть вашего запроса. Это позволяет вам делать (почти) все, что угодно, в рамках запроса. В целях безопасности использование операторов $where должно быть строго ограничено или исключено. Конечным пользователям никогда не следует разрешать использовать произвольные операторы $where.

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

1
2
> db.foo.insertOne({"apple" : 1, "banana" : 6, "peach" : 3})
> db.foo.insertOne({"apple" : 8, "spinach" : 4, "watermelon" : 4})

Мы хотели бы вернуть документы, где любые два поля одинаковы. Например, во втором документе spinach и watermelon имеют одно и то же значение, поэтому мы бы хотели, чтобы этот документ был возвращен. Маловероятно, что в MongoDB когда-либо появится условный оператор для этого, поэтому можно использовать оператор $where:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
> db.foo.find({"$where" : function () {
        for (var current in this) {
            for (var other in this) {
                if (current != other && this[current] == this[other]) {
                    return true;
                }
            }
        }
        return false;
    }}
);

Если функция возвращает значение true, документ будет частью набора результатов; если она вернет значение false, этого не произойдет.

Запросы с помощью оператора $where не следует использовать без крайней необходимости: они намного медленнее, по сравнению с обычными запросами. Каждый документ необходимо преобразовать из формата BSON в объект JavaScript, а затем прибегнуть к оператору $where. Индексы здесь также нельзя применять. Следовательно, вы должны использовать оператор $where только тогда, когда нет другого способа выполнить запрос. Можно сократить снижение производительности, используя другие фильтры запросов в сочетании с $where. Если это возможно, индекс будет использоваться для фильтрации на основе операторов, отличных от $where; оператор $where будет применяться только для точной настройки результатов. В MongoDB версии 3.6 был добавлен оператор $expr, позволяющий использовать выражения агрегации на языке запросов MongoDB. Он быстрее, чем $where, поскольку не выполняет код на JavaScript и рекомендуется в качестве замены этого оператора, где это возможно.

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

Комментарии