2014-11-22 3 views
0

Есть ли способ отсортировать по двум полям одновременно в mongodb? Так скажем, у нас есть следующие документы в коллекции:Mongodb сортировать по любому из двух полей

{ id: 'name1', last_1: 5, last_2: 2 }, 
{ id: 'name2', last_1: 1, last_2: 9 }, 
{ id: 'name3', last_1: 4, last_2: 3 } 

Я хочу, чтобы быть отсортированы в порядке убывания, проверяя как last_1 и last_2, так что результат будет: документ2 (9 в last_2), document1 (5 в последнем_1), документе3 (4 в последнем_1). Мне также нужно знать, в каком поле оно находится. Моя текущая агрегация выглядит следующим образом:

{ $group: 
     { _id: { id: '$name' }, 
     last_1: { $last: '$field1' }, 
     last_2: { $last: '$field2' }, 
     } 
     }, 
     { $sort : { /* don't know what to put in here */ } }, 
     { $limit: some_limit } 

UPD: Я, возможно, придется удалить сортировки/ограничение на все и использовать некоторые функции пользовательского узла для этого, потому что это выглядит как я не могу достичь этого, используя только монго, особенно потому, что дополнительным требованием было бы перечислить один и тот же документ дважды, если оба его поля больше, чем в других документах.

+0

Почти невозможно сказать без вашего собственного ввода, какое поле должно иметь приоритет в этом случае. Таким образом, единственным способом в настоящее время является присвоение весов этим полям для одного поля сортировки через структуру агрегации – Sammaye

+0

Ни один из них не должен иметь приоритет, опять же, после группового этапа, который у меня есть, скажем, 5 документов, с последними значениями двух полей и я хочу, чтобы mongo принимало все 10 значений (5 docs * 2 последних значения), сортировать их и упорядочивать эти документы на основе первых 5 значений после сортировки. –

+0

хорошо, вы говорите в своем примере, что doc 2 должен принимать last_2 как приоритет, так как это 9, тогда как doc1 должен принимать last_1 как приоритет, так как это 5, или я ошибаюсь? – Sammaye

ответ

2

Может быть что-то вроде этого,

db.test.aggregate([ 
    {$project: {name: 1, field1: 1, field2: 1}}, 
    {$group: {_id: '$name', field_1: { $last: '$field1' }, field_2: { $last: '$field2' }}}, 
    {$project: {name: 1, field_1: 1, field_2: 1, cmp: { $cmp: ['$field_2', '$field_1'] } }}, 
    {$sort: { cmp: -1, field_1: -1, field_2: -1 }} 
]) 
db.test.aggregate([ 
    {$project: {name: 1, field1: 1, field2: 1}}, 
    {$group: {_id: '$name', field_1: { $last: '$field1' }, field_2: { $last: '$field2' }}}, 
    {$project: { 
     name: 1, 
     field_1: 1, 
     field_2: 1, 
     largest: { $cond: [ {$gt: ['$field_2', '$field_1']}, '$field_2', '$field_1'] }  
    }}, 
    {$sort: { largest: -1 }} 
]) 
1

Ваше требование в том, чтобы sort документов в коллекции на основе полей, last_1 и last_2, в зависимости от того наиболее крупные из них могут быть агрегированы следующим образом:

  • Проект дополнительного поля, которое содержит большее значение между last_1 и last_2.
  • На основании этого поля sort записей в descending заказ.
  • Затем project обязательные поля.

агрегация код:

db.collection.aggregate([ 
{$project:{"id":"$id", 
      "last_1":1, 
      "last_2":1, 
      "sortField":{$cond:[ 
           {$gt:["$last_1","$last_2"]}, 
           "$last_1", 
           "$last_2"]}}}, 
{$sort:{"sortField":-1}}, 
{$project:{"_id":0, 
      "id":"$id", 
      "last_1":1, 
      "last_2":1}} 
]) 
+0

Хороший вариант, я только что переписал запрос и обновленный пример .. +1 от меня –

0

Ok, это то, как все это закончилось, я боялся, что это было бы слишком медленно сравнивать с чем-то MongoDB-родной, но на самом деле это не так уж плохо:

Test.aggregate(
     [ 
      { $match: 
      {'modified': { $gte: settings.period } } 
      }, 

      { $group: 
      { _id: { name: '$name' }, 
      last_1: { $last: '$field_1' }, 
      last_2: { $last: '$field_2' }, 
      } 
      } 
     ], 

     function (err, result) { 
      if (err) callback(err); 
      else { 
      var arr = []; 
      for (var i = 0; i < result.length; i++) { 
       var obj = result[i]; 
       arr.push({ id: obj._id, sort: obj.last_1 }); 
       arr.push({ id: obj._id, sort: obj.last_2 }); 
      } 
      arr.sort(compare).reverse(); 
      arr = arr.slice(0, settings.limit); 
      var arr2 = []; 
      for (i = 0; i < arr.length; i++) { 
       var id = arr[i].id; 
       var element = result.filter(function(element) { 
       return element._id == id; 
       }); 
       arr2.push(element[0]); 
      } 
      callback(null, arr2); 
      } 
     }); 
    ); 

function compare(a, b) { 
    if (a.sort < b.sort) 
    return -1; 
    if (a.sort > b.sort) 
    return 1; 
    return 0; 
} 
+0

Что вы подразумеваете под 'mongodb native'? Вы все сделали на стороне клиента. Это не способ сделать это, когда вы можете сделать это на стороне сервера. – BatScream

+0

@BatScream, это моя серверная сторона. –

+0

Нет, его нет. Вы все обработали в своей функции обратного вызова. – BatScream

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