2014-12-06 2 views
4

В моем метеора приложение, у меня есть огромная коллекция документов, каждый из которых с полем tags, в основном, как это:MongoDB: найти документы, которые соответствуют большинству тегов

{..., tags: ["a","b","c"], ...}, 
{..., tags: ["a","b","d"], ...}, 
{..., tags: ["b","c","e"], ...}, 
{..., tags: ["x","y","z"], ...}, 
.... 

Теперь я хочу, чтобы запросить коллекцию на сервер с некоторыми тегами, например: ["a","d","y"], и получить все результаты, которые соответствуют хотя бы одному тегу, и набор результатов отсортирован по количеству совпадающих тэгов. Так, в ExampleSet результат должен быть:

{..., tags: ["a","b","d"], ...}, 
{..., tags: ["a","b","c"], ...}, 
{..., tags: ["x","y","z"], ...} 

, поскольку первый документ имеет два матча, "a" и "d", а остальные два элемента имеют один матч, "a" и "y".

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

Как будет выглядеть запрос?

ответ

3

Я мог бы также использовать общую структуру mongoDB, если это необходимо.

Вы должны использовать агрегацию трубопровод, который может быть записан, как показано ниже:

  • Match документов, имеющих по меньшей мере, одно соответствующего значения в тегах массива.
  • Мы будем раскручивать и работать с массивом меток, поэтому сохраните копию массива меток в каждой записи.
  • Unwindtags массив.
  • Match записи, которые имеют значение своих тегов во входном массиве.
  • Group по полю _id и вычислить количество согласованных документов.
  • Sort группы, основанные на их количестве совпадений.
  • project обязательные поля вместе с оригинальной копией массива тегов, которые мы создали.

Код:

var inp = ["a","d","y"]; 

db.collection.aggregate([ 
{$match:{"tags":{$in:inp}}}, 
{$project:{"tagsCopy":"$tags","tags":1}}, 
{$unwind:"$tags"}, 
{$match:{tags:{$in:inp}}}, 
{$group:{"_id":"$_id","noOfMatches":{$sum:1},"tags":{$first:"$tagsCopy"}}}, 
{$sort:{noOfMatches:-1}}, 
{$project:{"_id":0,"noOfMatches":1,tags:1}} //remove noOfMatches and 
              //add other required 
              //fields which are necessary. 
]) 

о/р:

{ "noOfMatches" : 2, "tags" : [ "a", "b", "d" ] } 
{ "noOfMatches" : 1, "tags" : [ "x", "y", "z" ] } 
{ "noOfMatches" : 1, "tags" : [ "a", "b", "c" ] } 
+0

работает отлично! благодаря! – Hisako

+0

Most Welcome. ;-) В качестве побочного вопроса, почему вы выбираете meteor over nodejs, когда метеор имеет очень ограниченную поддержку агрегации? – BatScream

+1

https://atmospherejs.com/meteorhacks/aggregate <- например. Агрегация в Meteor работает нормально. Точка использования Meteor - это концепция моего приложения * кроме * этого запроса. Многие клиент-тяжелые вычисления распределены по активным пользователям и (мягкие) возможности в реальном времени. (сводный агрегатор новостей). – Hisako

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