2012-03-22 3 views
2

Mongo docs состояние:Монго пользовательских ключи сортировка

Функция ключей Монго может автоматически индексировать массивы значений.

Это хорошо. Но как насчет сортировки на основе мультики? Более конкретно, как сортировать коллекцию в соответствии с процентным соотношением массива?

К примеру, у меня есть образец [ 'fruit', 'citrus' ] и коллекция, которая выглядит следующим образом:

{ 
    title: 'Apples', 
    tags: [ 'fruit' ] 
}, 

{ 
    title: 'Oranges', 
    tags: [ 'fruit', 'citrus' ] 
}, 

{ 
    title: 'Potato', 
    tags: [ 'vegetable' ] 
} 

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

Какой самый эффективный и простой способ сделать это?

+0

Можете ли вы более ясно узнать, что такое цель? это сортировать в соответствии с процентным соотношением? например все документы, соответствующие всем элементам массива (фрукты и цитрусовые в этом случае), а затем те, которые соответствуют только плодам, а затем только цитрусовые и т. д.? – Barrie

+1

@ Барри, да, точно. Обновлен вопрос. – katspaugh

ответ

4

Начиная с MongoDB 2.1 аналогичное вычисление может быть выполнено с использованием структуры агрегации. Синтаксис нечто вроде

db.fruits.aggregate(
    {$match : {tags : {$in : ["fruit", "citrus"]}}}, 
    {$unwind : "$tags"}, 
    {$group : {_id : "$title", numTagMatches : {$sum : 1}}}, 
    {$sort : {numTagMatches : -1}}) 

который возвращает

{ 
    "_id" : "Oranges", 
    "numTagMatches" : 2 
}, 
{ 
    "_id" : "Apples", 
    "numTagMatches" : 1 
} 

Это должно быть намного быстрее, чем метод картографического уменьшить по двум причинам. Во-первых, поскольку реализация является родным C++, а не javascript. Во-вторых, поскольку «$ match» будет отфильтровывать элементы, которые не совпадают вообще (если это не то, что вы хотите, вы можете оставить часть «$ match» и изменить часть «$ sum», чтобы либо 1 или 0 в зависимости от того, равен ли тег «плод» или «цитрусовые» или нет).

Единственная оговорка здесь в том, что mongo 2.1 не рекомендуется для производства. Если вы работаете на производстве, вам нужно подождать 2.2. Но если вы просто экспериментируете самостоятельно, вы можете играть с 2.1, поскольку структура агрегации должна быть более высокой.

+0

Спасибо, matulef! Синтаксис тоже очень приятный. – katspaugh

2

Примечание: Следующие пояснения необходимы для Mongo 2.0 и более ранних версий. Для более поздних версий вы должны рассмотреть новую структуру агрегации.

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

db.plants.mapReduce(
    function() { 
     var matches = 0; 
     for (var i = 0; i < targetTerms.length; i++) { 
      var term = targetTerms[i]; 
      for (var j = 0; j < this.tags.length; j++) { 
       matches += Number(term === this.tags[j]); 
      } 
     } 
     emit(this._id, matches); 
    }, 

    function (prev, curr) { 
     var result = 0; 
     for (var i = 0; i < curr.length; i++) { 
      result += curr[i]; 
     } 
     return result; 
    }, 

    { 
     out: { inline: 1 }, 

     scope: { 
      targetTerms: [ 'fruit', 'oranges' ], 
     } 
    } 
); 

Вы бы вам передать ваши ['fruit', 'citrus' ] входные значения с помощью параметра scope в карте уменьшить вызов, как {targetTerms: ['fruit', 'citrus' ]} так, что они доступны в функции отображения выше.

+0

Спасибо, Николас! – katspaugh