MongoDB聚合:将单独的文档字段投影到一个数组字段中

3

我有一个这样的文档:

{fax: '8135551234', cellphone: '8134441234'}

有没有一种方法可以将这个文档投影到这个页面上(不需要小组阶段):
{
    phones: [{
        type: 'fax',
        number: '8135551234'
    }, {
        type: 'cellphone',
        number: '8134441234'
    }]
}

我可能需要一个组合操作符来完成这个任务,但如果有其他方法的话,我宁愿不用,因为我的查询还投影了几个其他字段,所有这些字段都需要在分组阶段使用$first

希望这样清楚明白。谢谢!


1
没有 $group 阶段是不可能的。 - BatScream
1
很遗憾,目前还没有。$project 阶段无法很好地将字段值投影到数组值中,请参见 SERVER-8141 - wdberkeley
@wdberkeley 当然可以做到。你只需要好好思考一下。$map 可以转换数组。 - Neil Lunn
不,问题在于字段名称是变化的。当不同类型的手机有任意数量的不同名称时,您必须构建所有可能字段名称的数组。请参见第三个评论。 - wdberkeley
实际上,@NeilLunn是正确的,我的评论是说可能有任意数量的电话,但可供选择的电话类型是有限的。谢谢你们两个的评论。 - inolasco
显示剩余4条评论
1个回答

4
MongoDB 2.6引入了$map运算符,它是一个数组转换运算符,可用于实现以下功能:
db.phones.aggregate([
    { "$project": {
        "phones": { "$map": {
            "input": { "$literal": ["fax","cellphone"] },
            "as": "el",
            "in": {
                "type": "$$el",
                "number": { "$cond": [
                     { "$eq": [ "$$el", "fax" ] },
                     "$fax",
                     "$cellphone"
                 ]}
             }
        }}
    }}
])

现在您的文档看起来正是您想要的样子。当然,诀窍是创建一个新数组,其中包含“传真”和“手机”的成员,然后通过匹配这些值使用新文档字段转换该数组。

当然,您也可以在早期版本中使用 $unwind$group 以类似的方式执行此操作,但效率不如此高:

db.phones.aggregate([
    { "$project": {
        "type": { "$const": ["fax","cellphone"] },
        "fax": 1,
        "cellphone": 1
    }},
    { "$unwind": "$type" },
    { "$group": {
        "_id": "_id",
        "phones": { "$push": { 
            "type": "$type",
            "number": { "$cond": [
                { "$eq": [ "$type", "fax" ] },
                "$fax",
                "$cellphone"
            ]}
        }}
    }}
])

当然,可以争论一下,如果你没有进行任何聚合操作,那么最好在代码中后处理集合结果。但这是另一种方法。

太棒了。不确定为什么我没想到这个,我知道 $map 操作符,但没想到可以将可能的电话类型作为数组传递给它 :) - inolasco

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接