I'm trying to dynamically sticky sort a collection of records with the value that is sticky being different with each query. Let me give an example. Here are some example docs:
{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 ...
Now suppose I want to display the names in alphabetical order by last name but I want to peg all the records with the first name "Joe" at the top.
In SQL this is fairly straight forward:
SELECT * FROM people ORDER first_name == 'Joe' DESC, last_name
The ability to put expressions in the sort criteria makes this trivial. Using the aggregation framework I can do this:
[ {$project: { first_name: 1, last_name: 1 offices: 1, sticky: {$cond: [{$eq: ['$first_name', 'Joe']}, 1, 0]} }}, {$sort: [ 'sticky': -1, 'last_name': 1 ]} ]
Basically I create a dynamic field with the aggregation framework that is 1 if the name if Joe and 0 if the name is not Joe then sort in reverse order. Of course when building my aggregation pipeline I can easily change 'Joe' to be 'Daniel' and now 'Daniel' will be pegged to the top. This is partially what I mean by dynamic sticky sorting. The value I am sticky sorting by will change query-by-query
Now this works great for a basic value like a string. The problem comes when I try to the same thing for a value that hold an array. Say I want to peg all users in 'FL' offices. With Mongo's native understanding of arrays I would think I can do the same thing. So:
[ {$project: { first_name: 1, last_name: 1 offices: 1, sticky: {$cond: [{$eq: ['$offices', 'FL']}, 1, 0]} }}, {$sort: [ 'sticky': -1, 'last_name': 1 ]} ]
But this doesn't work at all. I did figure out that if I changed it to the following it would put Joe Johnson (who is only in the FL office) at the top:
[ {$project: { first_name: 1, last_name: 1 offices: 1, sticky: {$cond: [{$eq: ['$offices', ['FL']]}, 1, 0]} }}, {$sort: [ 'sticky': -1, 'last_name': 1 ]} ]
But it didn't put Joe Blow at the top (who is in FL and GA). I believe it is doing simple match. So my first attempt doesn't work at all since $eq returns false since we are comparing an array to a string. The second attempt works for Joe Johnson because we are comparing the exact same arrays. But Joe Blow doesn't work since ['GA', 'FL'] != ['FL']. Also if I want to peg both FL and SC at the top I can't give it the value ['FL', 'SC'] to compare against.
Next I try using a combination of $setUnion and $size.
[ {$project: { first_name: 1, last_name: 1 offices: 1, sticky: {$size: {$setUnion: ['$offices', ['FL', 'SC']]}} }}, {$sort: [ 'sticky': -1, 'last_name': 1 ]} ]
I've tried using various combinations of $let and $literal but it always complains about me trying to pass a literal array into $setUnion's arguments. Specifically it says:
disallowed field type Array in object expression
Is there any way to do this?