запрос mongodb для сопоставления каждого элемента в массиве doc с условием - PullRequest
5 голосов
/ 18 мая 2011

У меня есть документы, аналогичные этому:

{_ id: 1, значения: [2,3,4]}

{_ id: 2, значения: [4]}

{_ id: 3, значения: [3,4,5,6,7,8,9,10,11]}

, в котором каждый документ имеет массив. Мне нужен запрос, который возвращает документ, только если КАЖДЫЙ элемент его массива соответствует желаемым критериям (а не если ЛЮБОЙ элемент соответствует).

Например. что-то вроде (но не)

{'values': {'$ gt': 1, '$ lt': 5}})

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

Очевидно, что mongodb использует неявное ИЛИ в запросах к массивам, тогда как мне нужно AND.

Полагаю, я мог бы вручную индексировать каждый элемент, например .:

collection.find ({values.0: {$ gt: 1, $ lt: 5}, values.1: {$ gt: 1, $ lt: 5}, ... values.n: {$ gt : 1, $ lt: 5}}) но это проблема с моими высокодинамичными массивами.

Есть ли лучший способ?

Примечание: я спрашивал об этом у пользователя mongodb, но, будучи новичком в mongodb, вызвал путаницу с оператором $ all. Здесь я обеспокоен массивом документов, а не массивом запросов. Кроме того, в этом числовом случае я понимаю, что можно написать запрос, который отрицает требуемый диапазон, но в целом я не смогу написать отрицание.

Ответы [ 5 ]

7 голосов
/ 18 мая 2011

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

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

db.col.find("this.values.every(function(v) { return (v > 1 && v < 5) })")

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

db.col.find("return this.values.every(function(v) { return (v > 1 && v < 5) })")
5 голосов
/ 02 февраля 2015

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

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

В вашем примере утверждение:

∀ x ∈ значения: x> 1 ∧ x <5 </p>

или «все значения> 1, а <5» эквивалентно </p>

∄ x ∈ значения: ¬ (x> 1 ∧ x <5) </p>

или «не существует значения, которое не > 1 и <5», которое по <a href="https://en.wikipedia.org/wiki/De_Morgan%27s_laws" rel="noreferrer"> законам де Моргана становится:

∄ x ∈ значения: x ≤1 ∨ x ≥ 5

или «нет значения, равного ≤ 1 или ≥ 5»

Последнее может быть выражено вMongoDB во многих отношениях, например:

> db.test.remove()
> db.test.insert({_id: 1, values: [2, 3, 4]})
> db.test.insert({_id: 2, values: [4]})
> db.test.insert({_id: 3, values: [3, 4, 5, 6, 7, 8, 9, 10, 11]})

> db.test.find({$nor: [{values: {$lte: 1}}, {values: {$gte: 5}}]})
{ "_id" : 1, "values" : [  2,  3,  4 ] }
{ "_id" : 2, "values" : [  4 ] }
1 голос
/ 18 мая 2011

Вы пожертвуете скоростью, но вы можете использовать выражение JavaScript , передаваемое непосредственно find() или $where.

.элементы в вашем массиве и возвращают true, только если все они удовлетворяют вашему условию.

1 голос
/ 18 мая 2011

Это невозможно с MongoDB AFAIK прямо сейчас.

Редактировать: Я исправлен. Возможно, это просто не индексируется, поэтому для меня это «невозможная» территория. Смотрите где ниже. Вы также можете карту уменьшить. Они похожи на карты «из тюрьмы» в MongoDB, но, как обычно, у этих карт есть серьезные недостатки по сравнению с реальным оператором.

0 голосов
/ 18 мая 2011

Нить

http://groups.google.com/group/mongodb-user/browse_thread/thread/dad19e28c1acbd49

объясняет ваши варианты.

Как писал «chx»: это невозможно. Теперь вы знаете функциональность операторов $ all и $ or. Это все, что вы имеете и получаете от MongoDB - ни больше, ни меньше.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...