2016-09-26 2 views
3

У меня есть документы с четырьмя полями: A, B, C, D Теперь мне нужно найти документы, в которых по меньшей мере три поля совпадают. Например:Выбор данных из MongoDB, где выполняются критерии K из N

запрос: A = A, B = B, C = C, D = D

Возвращенные документы:

  1. а, б, в, г (четыре из четырех мет)
  2. а, б, в (три из четырех мет)
  3. а, б, г (еще три из четырех мет)
  4. а, в, г (еще три из четырех мет)
  5. б, в, г (еще три из четырех встретились)

До сих пор я создал что-то вроде:

`(A=a AND B=b AND C=c) 
OR (A=a AND B=b AND D=d) 
OR (A=a AND C=c AND D=d) 
OR (B=b AND C=c AND D=d)` 

Но это некрасиво и подвержен ошибкам.

Есть ли лучший способ достичь этого? Также важна производительность запросов.

Я использую данные Spring, но я считаю, что это не имеет значения. Мой текущий код:

Criteria c = new Criteria(); 

    Criteria ca = Criteria.where("A").is(doc.getA()); 
    Criteria cb = Criteria.where("B").is(doc.getB()); 
    Criteria cc = Criteria.where("C").is(doc.getC()); 
    Criteria cd = Criteria.where("D").is(doc.getD()); 

    c.orOperator(
      new Criteria().andOperator(ca,cb,cc), 
      new Criteria().andOperator(ca,cb,cd), 
      new Criteria().andOperator(ca,cc,cd), 
      new Criteria().andOperator(cb,cc,cd) 
    ); 
    Query query = new Query(c); 

    return operations.find(query, Document.class, "documents"); 

ответ

1

То, как у вас есть это, вы должны сделать все перестановки в своем запросе. Вы можете использовать структуру агрегации для этого, не переставляя все комбинации. И это достаточно общего для любого K. Недостатком является то, что мне кажется, что вам нужен Mongodb 3.2+, а также Spring Data еще не поддерживает эти операционные системы: $filter$concatArrays

Но вы можете сделать это довольно легко с помощью драйвера java.

[ 
    { 
     $project:{ 
     totalMatched:{ 
      $size:{ 
       $filter:{ 
        input:{ 
        $concatArrays:[ ["$A"], ["$B"], ["$C"],["$D"]] 
        }, 
        as:"attr", 
        cond:{ 
        $eq:["$$attr","a"] 
        } 
       } 
      } 
     } 
     } 
    }, 
    { 
     $match:{ 
     totalMatched:{ $gte:3 } 
     } 
    } 
] 

Все, что вы делаете, это конкатенация значений всех полей, которые необходимо проверить в одном массиве. Затем выберите подмножество тех элементов, которые равны значению, которое вы ищете (или любое условие, которое вы хотите, если на то пошло) и, наконец, получите размер этого массива для каждого документа.

Теперь все, что вам нужно сделать, это $match документы, размер которых больше или равен тому, что вы хотите.

2

В настоящее время в MongoDB мы не можем сделать это непосредственно, так как мы не имеем никакой функциональности с поддержкой Перестановка/Combination от параметров запроса.

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

Использование Aggregation трубопровод

$projectwith records (A=a AND B=b) --> This will give the records which are having two conditions matching. (Наша цель состоит в том, чтобы найти записи, которые имеющие матчи на 3 из 4-й или 4 из 4 по данному условию) `

Next in the pipeline use OR condition (C=c OR D=d) to find the final set of records which yields our expected result. 

Надеется, что это Помогает!

Смежные вопросы