проверить, является ли поле подстрокой строки или текстового поиска в MongoDB - PullRequest
1 голос
/ 21 марта 2020

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

Пример Do c:

{
    "_id" : ObjectId("5e6ffe413f71835ae3aa4b60"),
    "f" : "Paul",
    "id" : 11811,
    "l" : "Green",
    "r" : 64
  }

, если строка is Paul Green Я хочу получить этот элемент, поэтому я попытался выполнить этот запрос:

db.getCollection('players').find({$or: [{'f': {'$regex': 'Paul Green', '$options': 'i'}},{'l': {'$regex': 'Paul Green', '$options': 'i'}}]})

, который не дал результатов. Я также хочу, чтобы поиски типа pele дали мне pelè

Как мне этого добиться?

1 Ответ

1 голос
/ 21 марта 2020

Обновленный ответ:

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

Так что я бы предложил, так как вы ' при поиске по двум полям f & l - я бы порекомендовал объединить два в одно поле fl и создать для него текстовый индекс таким образом, чтобы ваши запросы предназначались для одного поля, которое более эффективно для поисковых запросов. Проверьте ниже рекомендации:

Шаг 1: В случае, если вы не создали объединенное поле, вы можете сделать это сейчас с помощью этого запроса к MongoDB v >=4.2 (В более низкой версии вам нужно найти способ выполните либо Read Coll & update field или use aggregation + $out):

db.collection.update({},[{$addFields : {'fl': { $concat: [ "$f", " ", "$l" ] }}}],{multi:true})

Шаг 2: Создание текстового индекса в поле fl:

db.collection.createIndex( { fl: "text" } )

Шаг 3: Вы можете выполнять поиск, как показано ниже, Дополнительная проекция {fl :0} для удаления fl поля в ответ.

db.collection.find( { $text: { $search: "Paul Green" } }, {fl :0} )

Примечание: Теперь вы можете получить все документы, в которых f или l имеет Paul или Green или PAUL или GREEN или PAUL GREEN или Greèn или PAU или Pau или Gre или GRE , так что большая часть этого разбирается. Если вы не изучаете текстовый поиск, вы по-прежнему изучаете следующий подход.


Фактический ответ:

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

Но если вы хотите передать строку 'Paul Green' и проверить, что поле является подстрокой ввода, то обычное регулярное выражение вам не поможет. Но если вы используете MongoDB версии 4.2, вы можете сделать несколько вещей, как показано ниже:

Запрос 1:

db.collection.aggregate([
  /** Add a field which will be true if any of the field 'f' or 'l' is a sub-string of input (Case-insensitive) */
  {
    $addFields: {
      result: {
        $or: [
          { $regexMatch: { input: "Paul Green", regex: "$f", options: "i" } }, /** Usually input is field & regex is actual input value, we tricked it for our requirement */
          { $regexMatch: { input: "Paul Green", regex: "$l", options: "i" } }
        ]
      }
    }
  },
  /** Filter for all docs where result field is true (Which leave docs where 'f' or 'l' is sub-string) */
  { $match: { result: true } },
  /** Remove added field result */
  { $project: { result: 0 } }
]);

Тест: MongoDB-Playground

Примечание: Вышеупомянутый запрос будет работать, даже если отправить входную строку, например 'PaulGreen', но недостатком будет то, что он не даст вам результаты как Вы хотите сделать: поиск, как pele даст мне pelè , потому что, если вы хотите получить такие данные, вам нужно использовать параметры сортировки, которые нельзя использовать, если мы используем $ regexMatch . Итак, основываясь на ваших данных, вы можете сделать следующее:

Запрос 2:

Разделить строку на основе пробелов ['Paul', 'Green'] & передать запрос:

db.collection.aggregate(
  /** Filter docs if any of the word exists in any of the fields 'f' or 'l' */
  [
    {
      $match: {
        $or: [
          { f: { $in: ["Paul", "Green"] } },
          { l: { $in: ["Paul", "Green"] } }
        ]
      }
    }
  ],
  { collation: { locale: "fr", strength: 1 } } // Applied collation ignores case & diacritics
);

Примечание: Вышеупомянутый запрос может в основном выполнить вашу работу с версиями MongoDB> 3.4, но не будет работать, если вы хотите выполнить поиск что-то вроде 'PaulGreen', По какой-то причине сортировка этого запроса не работает на площадке mongodb - пожалуйста, проверьте его на реальной базе данных.

...