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

#mongodb #mongodb-query

#mongodb #mongodb-запрос

Вопрос:

Я пытаюсь оптимизировать запрос формы A.X = value OR B.Y.Z = value OR C.H = value в Mongodb. Механизм БД использует 3 разных индекса для выполнения подобного запроса, а затем объединяет результаты. Это несколько медленно, поэтому я решил поместить все в один массив и создать для него индекс с несколькими ключами. Итак, я создал индекс и этот запрос для обновления записей и его заполнения:

 {
  '$addFields': { 
    'AllowedEntries': [ '$A.X', '$B.Y.Z', '$C.H' ]
  } 
}
  

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

 {
  '$addFields': { 
    'AllowedEntries': { 
      '$map': { 
        'input': [ '$A.X', '$B.Y.Z', '$C.H' ], 
        'as': 'item', 
        'in': { 
          'columns': { 
            '$filter': { 
              'input': '$$item', 
              'as': 'elt', 
              'cond': { '$ne': [ '$$elt', null ] } 
            } 
          }
        }
      } 
    } 
  } 
}
  

Который не работает из-за input to $filter must be an array not binData ошибки. Как я могу сделать это атомарно? Теоретически я мог бы выполнить этот запрос, а затем извлечь нули, но мне бы очень хотелось сделать это за одно обновление.

Комментарии:

1. $map не должен быть обязательным, $filter должен быть в состоянии это сделать.

2. Не могли бы вы привести пример? Я не уверен, что понял вашу идею

3. Оператор $filter предназначен для выбора элементов из массива на основе логического условия, что вы и пытаетесь сделать. Посмотрите пример на docs.mongodb.com/manual/reference/operator/aggregation/filter /…

4. Прохладный. Сработало как шарм. Возможно ли не получать только уникальные значения? Я пытался $addToSet , но не удалось. Также вы не хотите опубликовать ответ? Я отмечу это, так как это помогло мне.

Ответ №1:

В итоге я пришел к следующему решению: поместить уникальные ненулевые элементы в новое поле. Большое спасибо @Joe за помощь

 {
  '$addFields': { 
    'AllowedEntries': { 
      '$setUnion': [[], { 
        '$filter': { 
          'input': [  '$A.X', '$B.Y.Z', '$C.H' ], 
          'as': 'elt', 
          'cond': '$$elt' 
        } 
      }] 
    } 
  } 
}
  

обратите внимание, что $setUnion вместо используется с пустым массивом $addToSet , потому что последний работает с именами столбцов, в то время как первый работает с любым выражением, которое в нашем случае является фильтром.