我正在尝试对某些搜索结果进行评分/排名。
通常这有效:
(userIds
这里是一组代表我们想要评分/排名的用户的ID,SomeModel
包含与那些为我们提供排序标准的用户相关联的资产。)
SomeModel.aggregate([
{$match: {ownerId: {$in:userIds}}},
//Do stuff here to generate a score for the results. This works fine...
...
//at this point you'll have an array like this: {userId:<id>, score:<number>}[]
//push all those results into a field called 'origin' so we can add another
//field with the full set if IDs, merge them, and return them...
{$group: {
_id:0,
origin: {
$push: '$$ROOT'
}
}},
//Add back the full set with project, giving a score of 0 for each.
...
]).then( results => {
//enjoy your results that include all matched IDs plus the
//non-matched ones, who then get a score of 0.
});
只要第一个$match
返回一些结果,这一切都可以正常工作。如果$match
没有返回任何结果,那么$group
步骤似乎根本不会产生任何结果,就像我期望它至少返回一样:
{
_id:0,
origin:[]
}
......但事实并非如此。如果我此时查看结果,我只需[]
。
我尝试更改$group
步骤来检查这个:
{$group: { //make these an array so we can merge it....
_id:0,
origin: {
$push :{
$cond:{
if: {$eq:[{$size : '$$ROOT'}, 0]},
then: [null],
else: '$$ROOT'
}
}
}
}},
...但后来我收到错误“$ size的参数必须是一个数组,但是类型为:object”。
这样做的正确方法是什么?为了清楚起见,我想创建一个容器对象,该对象将结果中的结果保存为字段origin
中的数组。 (然后我就可以将这些与我开始的完整列表连接起来并得到一个正确的排序列表。)
如果管道当前包含结果,则此方法有效,但如果不包含,则组步骤不执行任何操作。
所需的输入/输出:
我的问题特别针对$group
阶段,所以我会专注于此。
示例1: 此示例与上面的代码一起正常工作。
输入:
[ {ownerId: <ID A>, score: 234}, {ownerId: <ID B>, score: 265}]
$group
期望的输出:
[{
_id:0,
origin:[ {ownerId: <ID A>, score: 234}, {ownerId: <ID B>, score: 265}]
}]
实际输出:匹配!
示例2: 此示例无法正常使用上述代码。
输入:
[]
$group
期望的输出:
[{
_id:0,
origin:[]
}]
实际输出:
[]
答案 0 :(得分:2)
聚合管道的概念是,在执行管道时,MongoDB将运营商相互管道化。 &#34;管&#34;这里采用Linux的含义:运算符的输出成为以下运算符的输入。每个运算符的结果是一个新的文档集合。在上面的Mongo执行管道如下:
collection | $match | $group | $project => result
这意味着如果$match
步骤不匹配给定条件的管道中的任何文档,Mongo将不会进一步管道,因此您得到一个空结果,因为管道以{{结尾1}},它没有更进一步。
然而,你可以做的是在$match
管道中注入条件,但是如果有大量的集合会导致一些性能损失。这是因为$group
步骤将处理集合中的所有文档,而不是通过使用$group
返回那些匹配条件作为第一优先级的文档来减少进入管道的文档数量。
使用此路线,将您的$match
阶段视为具有以下条件的第一个管道步骤:
$group