javascript - $$ROOT 没有结果时无法分组。 (MongoDB)

标签 javascript mongodb mongoose aggregation-framework

我正在尝试对一些搜索结果进行评分/排名。

通常这有效: (userIds 是一组 ID,代表我们想要评分/排名的用户,SomeModel 包含与这些用户关联的 Assets ,这些 Assets 为我们提供了排序标准。)

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 的参数必须是一个数组,但类型为:对象”。

正确的做法是什么?明确地说,我想创建一个容器对象,将管道中该点的结果作为字段 origin 中的数组保存。 (然后我能够将这些与我开始使用的完整列表连接起来并获得正确的排序列表)。

如果管道当前包含结果,则此方法有效,但如果不包含,则组步骤不执行任何操作。

所需的输入/输出:

我的问题特别出在 $group 阶段,所以我会专注于此。

示例 1: 此示例与上述代码一起正常工作。

输入:

[ {ownerId: <ID A>, score: 234}, {ownerId: <ID B>, score: 265}]

$组

期望的输出:

[{
    _id:0,
    origin:[ {ownerId: <ID A>, score: 234}, {ownerId: <ID B>, score: 265}]

}]

实际输出:匹配!

示例 2: 此示例无法与上述代码一起正常工作。

输入:

[]

$组

期望的输出:

[{
    _id:0,
    origin:[]

}]

实际输出:

[]

最佳答案

聚合管道的概念是,当执行管道时,MongoDB 将操作符通过管道传递给彼此。这里的“管道”取Linux的意思:一个算子的输出成为后面算子的输入。每个运算符的结果是一个新的文档集合。在上面的 Mongo 中执行管道如下:

collection | $match | $group | $project => result

这意味着如果 $match步骤与给定条件的管道中的任何文档都不匹配,Mongo 将不会进一步传输任何内容,因此您得到一个空结果,因为管道以 $match 结尾, 它不会走得更远。

然而,您可以做的是在 $group 中注入(inject)条件。 pipeline 但如果集合很大,这将对性能造成一些影响。这是因为 $group步骤将处理集合中的所有文档,而不是通过使用 $match 仅返回符合条件的文档作为第一优先级来减少进入管道的文档数量。 .

通过这条路线,考虑您的 $group阶段作为管道的第一个步骤,条件为:

[
    { "$group": { 
        "_id": 0,
        "origin": {
            "$addToSet": {
                "$cond": [
                    { "$in": ["$ownerId", userIds] },
                    "$$ROOT", null
                ]
            }
        }
    } },
    { "$project": {
        "origin": {
            "$filter": {
                "input": "$origin",
                "as": "el",
                "cond": { "$ne": ["$$el", null] }
            }
        }
    } }
]

关于javascript - $$ROOT 没有结果时无法分组。 (MongoDB),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49077775/

相关文章:

javascript - 从右到左切换 Div

node.js - 如何使用 MongoLab 在 Heroku 上设置 MongoDB 数据库?

javascript - 更新 mongodb 中的嵌套值

node.js - Mongoose 对子文档中的项目进行计数

javascript - 在 Node js 和 mongoose 中编写查询并从数据库返回一个值

node.js - 无法删除 json 元素

javascript - 如何找到没有id的li的索引?

javascript - 使用一个数组中的值作为键来查找另一个数组中的匹配项

javascript - 使用 jQuery 垂直居中 div

MongoDB shell 命令行身份验证失败