** ОБНОВЛЕНО **
Привет 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-вывод:
Как уже упоминалось в @Neil ответ как и в этом Джира Билет sets
будет неупорядоченным.
Расширение ответа Нейла это может быть достигнуто с помощью следующих шагов:
Unwind
набор.Sort
на основании поля.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. Пожалуйста, проверьте и исправьте любые незначительные ошибки.
Истинный случай состоит в том, что, конечно, «набор» не считается упорядоченным каким-либо образом, поэтому, если вы ожидаете, что элементы упорядочены, вам нужно обрабатывать их так, чтобы это не было «набор».
Лучше, чем «раскручивать» массив, созданный $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
а затем снова сгруппировать результаты.