Как отсортировать $ addToSet внутри группы $?

** ОБНОВЛЕНО **

Привет MongoDB-Эксперты,

Я стажер-разработчик программного обеспечения, и у меня мало опыта работы с MongoDB.

Я хочу отсортировать определенные значения в поле $ addToSet. Я в основном хочу отсортировать «фирмен» (компании) в группе $. Как я могу это сделать?

Большое спасибо за вашу помощь заранее.
t.koelpin

Вот мой PHP-код, который я использовал:

$sumQuery = array(
array(
'$match' => array(
'startzeit' => array(
'$gte' => new MongoDate(strtotime("2015-01-01 01:00:00")),
'$lte' => new MongoDate(strtotime("2015-01-01 08:00:00"))
)
)
),
array(
'$group' => array(
'_id' => array(
'portal' => '$portal',
'protokoll' => '$protokoll'
),
'daten' => array(
'$addToSet' => array(
'firmen' => '$firma'
)
),
'count' => array(
'$sum' => 1
)
)
),
array(
'$sort' => array(
'_id' => 1
)
),
array(
'$project' => array(
'_id' => 0,
'portal' => '$_id.portal',
'protokoll' => '$_id.protokoll',
'firmen' => '$daten.firmen',
'connections' => '$count'
)
)
);

Вот мой несортированный PHP-вывод:

несортированный PHP-вывод

0

Решение

Как уже упоминалось в @Neil ответ как и в этом Джира Билет sets будет неупорядоченным.

Расширение ответа Нейла это может быть достигнуто с помощью следующих шагов:

  1. Unwind набор.
  2. Sort на основании поля.
  3. Group поле с $push,

Как unwinding а также grouping не изменит порядок результата, единственной задачей является сохранение значения Connections, Это может быть достигнуто с помощью $first или же $max оператор.

Вот модифицированный код PHP для достижения этой цели.

    $sumQuery = array(
array(
'$match' => array(
'startzeit' => array(
'$gte' => new MongoDate(strtotime("2015-01-01 01:00:00")),
'$lte' => new MongoDate(strtotime("2015-01-01 08:00:00"))
)
)
),
array(
'$group' => array(
'_id' => array(
'portal' => '$portal',
'protokoll' => '$protokoll'
),
'daten' => array(
'$addToSet' => array(
'firmen' => '$firma'
)
),
'count' => array(
'$sum' => 1
)
)
),

//Unwinding daten.firmen
array('$unwind' =>  '$daten.firmen'),

//Sorting the values
array(
'$sort' => array(
'daten.firmen' => 1
)
),

//$push creates an array so the sorted order is preserved
array(
'$group' => array(
'_id' => array(
'portal' => '$_id.portal',
'protokoll' => '$_id.protokoll'
),
'daten' => array(
'$push' => array(
'firmen' => '$daten.firmen'
)
),
'count' => array(
'$max' => '$count'
)
)
),
array(
'$sort' => array(
'_id' => 1
)
),
array(
'$project' => array(
'_id' => 0,
'portal' => '$_id.portal',
'protokoll' => '$_id.protokoll',
'firmen' => '$daten.firmen',
'connections' => '$count'
)
)
);

PS: я не уверен насчет синтаксиса для PHP. Пожалуйста, проверьте и исправьте любые незначительные ошибки.

1

Другие решения

Истинный случай состоит в том, что, конечно, «набор» не считается упорядоченным каким-либо образом, поэтому, если вы ожидаете, что элементы упорядочены, вам нужно обрабатывать их так, чтобы это не было «набор».

Лучше, чем «раскручивать» массив, созданный $addToSet по сути просто $group на значения, которые должны содержаться в массиве в первую очередь, как часть ключа группировки. Все в ключе группировки по определению является «отличным» значением, так что если вы $group там сначала вы можете снова $group позже «свернуть» массив после обработки элементов $sort,

Это сэкономит много накладных расходов при первом сворачивании массива с $addToSet и затем снова «ненормализовать» только для сортировки контента, поскольку это может быть довольно дорого:

$sumQuery = array(
array(
'$match' => array(
'startzeit' => array(
'$gte' => new MongoDate(strtotime("2015-01-01 01:00:00")),
'$lte' => new MongoDate(strtotime("2015-01-01 08:00:00"))
)
)
),
array(
'$group' => array(
'_id' => array(
'portal' => '$portal',
'protokoll' => '$protokoll',
'daten' => '$firmen'
),
'count' => array(
'$sum' => 1
)
)
),
array(
'$sort' => array(
'_id' => 1
)
),
array(
'$group' => array(
'_id' => array(
'portal' => '$_id.portal',
'protokoll' => '$_id.protokoll'
),
'daten' => array( '$push' => '$_id.daten'),
'count' => array(
'$sum' => '$count'
)
)
),
array(
'$project' => array(
'_id' => 0,
'portal' => '$_id.portal',
'protokoll' => '$_id.protokoll',
'firmen' => '$daten',
'connections' => '$count'
)
)
);

Отмечая также, что если вы ожидаете определенный «порядок полей» от $project на этапе, то ни одно из имен полей не может присутствовать на более ранней стадии, в противном случае MongoDB просто «копирует» этот вывод в более раннюю позицию документа в качестве оптимизации.

Как правило, рекомендуется не использовать такой $project этап в конце вашего конвейера и просто принять результаты как возвращенные. Это добавляет дополнительный проход к возвращаемым результатам для переименования поля. Поэтому, если здесь не требуется никаких вычислений, вы просто расходуете память и циклы ЦП ради переорганизации имен полей.

Это обычно лучше обрабатывать в клиентском коде, получающем результат, чем заставляя конвейер агрегации делать это. Но если ты $group в два этапа, будучи первым на более широком уровне и с $sort между прочим, тогда это ваш лучший способ вернуть «отдельный» список без ущерба для производительности $unwind а затем снова сгруппировать результаты.

1

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector