Я пытаюсь динамически сортировать набор записей со значением, которое является липким, разным для каждого запроса. Позвольте мне привести пример. Вот несколько примеров документов:
{first_name: 'Joe', last_name: 'Blow', offices: ['GA', 'FL']}
{first_name: 'Joe', last_name: 'Johnson', offices: ['FL']}
{first_name: 'Daniel', last_name: 'Aiken', offices: ['TN', 'SC']}
{first_name: 'Daniel', last_name: 'Madison', offices: ['SC', 'GA']}
... a bunch more names ...
Теперь предположим, что я хочу отобразить имена в алфавитном порядке по фамилии, но я хочу привязать все записи с именем «Джо» вверху.
В SQL это довольно прямолинейно:
SELECT * FROM people ORDER first_name == 'Joe' DESC, last_name
Возможность помещать выражения в критерии сортировки делает это тривиальным. Используя структуру агрегации, я могу сделать это:
[
{$project: {
first_name: 1,
last_name: 1
offices: 1,
sticky: {$cond: [{$eq: ['$first_name', 'Joe']}, 1, 0]}
}},
{$sort: [
'sticky': -1,
'last_name': 1
]}
]
В основном я создаю динамическое поле со структурой агрегации, которая равна 1, если имя, если Джо, и 0, если имя не Джо, а затем сортируется в обратном порядке. Конечно, при построении моего конвейера агрегации я могу легко изменить «Джо» на «Дэниел», и теперь «Дэниел» будет привязан к вершине. Это отчасти то, что я имею в виду под динамической липкой сортировкой. Значение, по которому я придерживаюсь сортировки, будет меняться от запроса к запросу.
Теперь это отлично работает для базового значения, такого как строка. Проблема возникает, когда я пытаюсь сделать то же самое для значения, содержащего массив. Скажем, я хочу привязать всех пользователей в офисах FL. Я думаю, что с родным пониманием массивов Mongo я могу сделать то же самое. Так:
[
{$project: {
first_name: 1,
last_name: 1
offices: 1,
sticky: {$cond: [{$eq: ['$offices', 'FL']}, 1, 0]}
}},
{$sort: [
'sticky': -1,
'last_name': 1
]}
]
Но это вообще не работает. Я понял, что если я изменю его на следующий, Джо Джонсон (который работает только в офисе Флориды) будет наверху:
[
{$project: {
first_name: 1,
last_name: 1
offices: 1,
sticky: {$cond: [{$eq: ['$offices', ['FL']]}, 1, 0]}
}},
{$sort: [
'sticky': -1,
'last_name': 1
]}
]
Но это не сделало Джо Блоу лидером (который работает во Флориде и Джорджии). Я считаю, что это простое совпадение. Итак, моя первая попытка вообще не работает, так как $eq возвращает false, так как мы сравниваем массив со строкой. Вторая попытка работает для Джо Джонсона, потому что мы сравниваем одни и те же массивы. Но Joe Blow не работает, так как ['GA', 'FL'] != ['FL']. Кроме того, если я хочу привязать FL и SC вверху, я не могу указать значение ['FL', 'SC'] для сравнения.
Затем я пытаюсь использовать комбинацию $setUnion и $size.
[
{$project: {
first_name: 1,
last_name: 1
offices: 1,
sticky: {$size: {$setUnion: ['$offices', ['FL', 'SC']]}}
}},
{$sort: [
'sticky': -1,
'last_name': 1
]}
]
Я пытался использовать различные комбинации $let и $literal, но он всегда жалуется на то, что я пытаюсь передать литеральный массив в аргументы $setUnion. В частности, говорится:
disallowed field type Array in object expression
Есть какой-либо способ сделать это?