Массив запросов для размещения «только» элементов в диапазоне - PullRequest
0 голосов
/ 28 мая 2018

Предположим, у меня есть следующие документы.

{ "_id" : 1, "score" : [ -1, 3 ] }
{ "_id" : 2, "score" : [ 1, 5 ] }
{ "_id" : 3, "score" : [ 5, 5 ] }
{"_id" : 4, "score" : [ 2, 1, 5 ]}

Если я хочу найти документы со всеми элементами в массиве оценок от 3 до 6 включительно, как я могу создать запрос с {$gte:3} и {$lte:6}?

Итак, должно возвращаться только:

 { "_id" : 3, "score" : [ 5, 5 ] }

1 Ответ

0 голосов
/ 28 мая 2018

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

 var start = 3,
     end = 6;

 var range = Array(end - start + 1).fill(1).map(e => start++);

 db.scores.find({
   "score": {
     "$elemMatch": { "$gte": start, "$lte": end },
     "$not": {
       "$elemMatch": { "$nin": range }
     }
   }
 })

Вернет:

 { "_id" : 3, "score" : [ 5, 5 ] }

Поскольку это единственный элемент, который содержит что-то, попадающее в этот диапазон «только».

ЕСЛИ у вас есть ограничение, когда элементы имеют слишком много возможных значений для перечисления всего«диапазон», то вы либо используете $not для «условия диапазона»:

db.scores.find({
  "score": {
     "$elemMatch": { "$gte": 3, "$lte": 6 },
     "$not": {
       "$elemMatch": {
         "$not": { "$gte": 3, "$lte": 6 }
       }
     }
  }
})

Или поочередно обрабатываете с дополнительным вычисленным условием,

Либоиспользуя $expr:

 db.scores.find({
   "score": { "$elemMatch": { "$gte": 3, "$lte": 6 } },
   "$expr": {
     "$allElementsTrue": {
       "$map": {
         "input": "$score",
         "in": { 
           "$and": [
             { "$gte": [ "$$this", 3 ] },
             { "$lte": [ "$$this", 6 ] }
           ]
         }
       }
     }
   }
 })

или $redact до MongoDB 3.6

db.scores.aggregate([
  { "$match": { "score": { "$elemMatch": { "$gte": 3, "$lte": 6 } } } },
  { "$redact": {
    "$cond": {
      "if": {
        "$allElementsTrue": {
          "$map": {
            "input": "$score",
            "in": { 
              "$and": [
                { "$gte": [ "$$this", 3 ] },
                { "$lte": [ "$$this", 6 ] }
              ]
            }
          }
        }
      },
      "then": "$$KEEP",
      "else": "$$PRUNE"
    }
  }}
])

или даже $where с использованием условия JavaScript для сопоставления, когда ваша MongoDB не поддерживает ничего из перечисленного:

db.scores.find({
  "score": { "$elemMatch": { "$gte": 3, "$lte": 6 } },
  "$where": function() {
    return this.score.every(e => e >= 3 && e <= 6)
  }
})

Во всех случаях вы действительно хотите, чтобы это "положительное" условие для $elemMatch, чтобы найти эти элементы "в пределах диапазона"архивирование индекса в этом поле .Ни один из других методов либо с использованием $not и $nin, либо с помощью условия агрегации $allElementsTrue или Array.every() может реально посмотреть на «индекс», чтобы выполнить условие.Они просто используются во всех случаях как «дополнительный фильтр», из которого можно «исключить» любые «потенциальные» совпадающие документы через «диапазон» из возможных результатов.

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