Mongodb - как найти записи, которые содержат определенный массив ключевых слов - PullRequest
7 голосов
/ 12 февраля 2012

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

{a:[1,2]}
{a:[1,3,8]}
{a:[1,2,5]}
{a:[3,5,1]}
{a:[4,5]}

Если я введу массив [1,2,3,5] для поиска, тогда я хочу получить:

{a:[1,2]}
{a:[1,2,5]}
{a:[3,5,1]}

Каждый из них является подмассивом [1,2,3,5].

Любая идея?

Пожалуйста, не используйте гдепункт (когда это возможно).Спасибо!

Ответы [ 2 ]

8 голосов
/ 12 февраля 2012

В mongodb это просто сделать, но сложнее всего подготовить данные для запроса. Позвольте мне объяснить, что в одер

Простая часть

Вы можете использовать $in, чтобы найти подходящие элементы в массиве. Давайте попробуем

db.coll.find({a:{$in:[1,2,3,5]})

и результат

{ "_id" : ObjectId("4f37c41739ed13aa728e9efb"), "a" : [ 1, 2 ] }
{ "_id" : ObjectId("4f37c42439ed13aa728e9efc"), "a" : [ 1, 3, 8 ] }
{ "_id" : ObjectId("4f37c42c39ed13aa728e9efd"), "a" : [ 1, 2, 5 ] }
{ "_id" : ObjectId("4f37c43439ed13aa728e9efe"), "a" : [ 3, 5, 1 ] }
{ "_id" : ObjectId("4f37c43e39ed13aa728e9eff"), "a" : [ 4, 5 ] }

ооо, это не тот результат, который мы ожидали. Да, потому что $ in возвращает элемент, если найден какой-либо соответствующий элемент (не обязательно все).

Таким образом, мы можем исправить это, передав точные элементы массива в $ in, например, если мы хотим найти элементы, соответствующие этим точным массивам {a: [1,2]} {a: [1,2,5] } и {a: [4,5,6]}

db.coll.find({a:{$in:[[1,2],[1,2,5],[4,5,6]]}})

вы получите

 { "_id" : ObjectId("4f37c41739ed13aa728e9efb"), "a" : [ 1, 2 ] }
 { "_id" : ObjectId("4f37c42c39ed13aa728e9efd"), "a" : [ 1, 2, 5 ] }

Вот и все

Самая сложная часть

Самая сложная часть - это формирование всех возможных комбинаций вашего входного массива [1,2,3,5]. Вам нужно найти способ получить всю комбинацию исходного массива (от вашего клиента) и передать его в $ in.

Например, этот метод JS даст вам все комбинации данного массива

var combine = function(a) {
  var fn = function(n, src, got, all) {
    if (n == 0) {
      if (got.length > 0) {
        all[all.length] = got;
      }
      return;
    }
    for (var j = 0; j < src.length; j++) {
      fn(n - 1, src.slice(j + 1), got.concat([src[j]]), all);
    }
    return;
  }
  var all = [];
  for (var i=0; i < a.length; i++) {
    fn(i, a, [], all);
  }
  all.push(a);
  return all;
}

>> arr= combine([1,2,3,5])

даст вам

[
    [
        1
    ],
    [
        2
    ],
    [
        3
    ],
    [
        5
    ],
    [
        1,
        2
    ],
    [
        1,
        3
    ],
    [
        1,
        5
    ],
    [
        2,
        3
    ],
    [
        2,
        5
    ],
    [
        3,
        5
    ],
    [
        1,
        2,
        3
    ],
    [
        1,
        2,
        5
    ],
    [
        1,
        3,
        5
    ],
    [
        2,
        3,
        5
    ],
    [
        1,
        2,
        3,
        5
    ]
]

и вы можете передать это arr в $, чтобы найти все элементы взаимодействия

     db.coll.find({a:{$in:arr}})

даст вам

{ "_id" : ObjectId("4f37c41739ed13aa728e9efb"), "a" : [ 1, 2 ] }
{ "_id" : ObjectId("4f37c42c39ed13aa728e9efd"), "a" : [ 1, 2, 5 ] }

Подождите !, все еще не возвращаются два оставшихся возможных предмета.

Потому что хорошо посмотри на arr, он находит только комбинацию. он возвращает [1,3,5], но данные в документе [3,5,1]. Поэтому ясно, что $in проверяет элементы в заданном порядке (странно!).

Итак, теперь вы понимаете, что действительно сложно сравнивать запрос mongodb !. Вы можете изменить приведенный выше код бывшей комбинации JS, чтобы найти возможную перестановку для каждой комбинации и передать ее в mongodb $in. Вот и вся хитрость.

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

0 голосов
/ 13 февраля 2012

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

Следуя инструкциямВ предложении Трэвиса в комментариях вы должны выполнить следующие шаги:

  1. Определить функцию JS для достижения ваших желаний (поскольку в MongoDB нет собственного способа сделать это);функция на сервере;
  2. Используйте функцию в $where.

Если определить вашу функцию для использования только с этим конкретным свойством (* в данном случае a),Вы можете пропустить шаг 2. Однако, поскольку это может быть полезной функцией для других свойств других документов, я определил более общую функцию, которую необходимо сохранить на сервере, чтобы использовать AFAIK (я новичок в Mongoтоже).

Ниже приведены мои тесты на оболочке монго:

<--! language: lang-js -->

// step 1: defining the function for your specific search
only = function(property, values) { 
  for(var i in property) if (values.indexOf(property[i]) < 0) return false
  return true
}

// step 2: saving it on the server
db.system.js.save( { _id : 'only', value : only } )

// step 3: using the function with $where
db.coll.find({$where: "only(this.a, [1,2,3,5])"})

С 5 объектами, которые вы указали в вопросе, вы получите:

{ "_id" : ObjectId("4f3838f85594f902212eb532"), "a" : [ 1, 2 ] }
{ "_id" : ObjectId("4f3839075594f902212eb534"), "a" : [ 1, 2, 5 ] }
{ "_id" : ObjectId("4f38390e5594f902212eb535"), "a" : [ 3, 5, 1 ] }

Недостатком является производительность. Подробнее.

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