【发布时间】:2014-05-20 00:32:29
【问题描述】:
我正在尝试对一组记录进行动态粘性排序,每个查询的粘性值都不同。让我举个例子吧。以下是一些示例文档:
{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 ...
现在假设我想按姓氏的字母顺序显示姓名,但我想将所有记录与顶部的名字“Joe”挂钩。
在 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
]}
]
基本上,我使用聚合框架创建一个动态字段,如果名称为 Joe,则为 1,如果名称不是 Joe,则为 0,然后按相反顺序排序。当然,在构建我的聚合管道时,我可以轻松地将“Joe”更改为“Daniel”,现在“Daniel”将与顶部挂钩。这部分是我所说的动态粘性排序的意思。我的粘性排序值将逐个查询改变
现在这对于像字符串这样的基本值非常有用。当我尝试对包含数组的值进行相同的操作时,问题就来了。假设我想锁定“FL”办公室中的所有用户。凭借 Mongo 对数组的原生理解,我认为我可以做同样的事情。所以:
[
{$project: {
first_name: 1,
last_name: 1
offices: 1,
sticky: {$cond: [{$eq: ['$offices', 'FL']}, 1, 0]}
}},
{$sort: [
'sticky': -1,
'last_name': 1
]}
]
但这根本不起作用。我确实发现,如果我将其更改为以下内容,它将把 Joe Johnson(他只在 FL 办公室)放在首位:
[
{$project: {
first_name: 1,
last_name: 1
offices: 1,
sticky: {$cond: [{$eq: ['$offices', ['FL']]}, 1, 0]}
}},
{$sort: [
'sticky': -1,
'last_name': 1
]}
]
但这并没有让 Joe Blow 位居榜首(他在佛罗里达州和乔治亚州)。我相信它正在做简单的匹配。所以我的第一次尝试根本不起作用,因为 $eq 返回 false 因为我们正在将数组与字符串进行比较。第二次尝试适用于 Joe Johnson,因为我们正在比较完全相同的数组。但是自从 ['GA', 'FL'] != ['FL'] 之后,Joe Blow 就不起作用了。另外,如果我想将 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
有什么办法吗?
【问题讨论】:
标签: mongodb aggregation-framework