需要从MongoDB集合中生成结构化文档

时间:2018-09-03 17:24:50

标签: mongodb mongoose mongodb-query aggregation-framework

我们有一个MongoDB collection像这样:

{
        a : string, nullable
        b : string, nullable
        c : boolean, not nullable
        d : string, nullable
        e : number, nullable 
}

我们需要这样的结果:

{
       ab : {
              a: <count of a where a is not blank or null>,
              b: <count of b where b is not blank or null>
            },
        c : {
              true: <count of c where c true>,
              false: <count of c where c false>
            },
        d : [<all distinct/unique values of d],
        e : {
              average : <average value of e>,
              min     : <minimum value of e>,
              max     : <maximum value of e>
            }
}   
  

我们不希望触发多个find查询并在内存中处理结果以显示结果。

我们如何仅使用MongoDB的查询来实现这一目标?任何建议将不胜感激

1 个答案:

答案 0 :(得分:1)

您需要运行多个管道,然后合并结果。使用$facet运算符可以实现。尝试以下查询:

db.col.aggregate([
    {
        $facet: {
            q1: [
                { $match: { a: { $exists: true, $ne: null }  } },
                { $count: "total" }
            ],
            q2: [
                { $match: { b: { $exists: true, $ne: null }  } },
                { $count: "total" }
            ],
            q3: [
                { $match: { c: true } },
                { $count: "total" }
            ],
            q4: [
                { $match: { c: false } },
                { $count: "total" }
            ],
            q5: [
                {
                    $group: {
                        _id: null,
                        unique: { $addToSet: "$d" }
                    }
                }
            ],
            q6: [
                {
                    $group: {
                        _id: null,
                        average: { $avg: "$e" },
                        min: { $min: "$e" },
                        max: { $max: "$e" },
                    }
                }
            ],
        }
    },
    {
        $project: {
            q1: { $arrayElemAt: [ "$q1", 0 ] },
            q2: { $arrayElemAt: [ "$q2", 0 ] },
            q3: { $arrayElemAt: [ "$q3", 0 ] },
            q4: { $arrayElemAt: [ "$q4", 0 ] },
            q5: { $arrayElemAt: [ "$q5", 0 ] },
            q6: { $arrayElemAt: [ "$q6", 0 ] }
        }
    },
    {
        $project: {
            "ab.a": { $ifNull: [ "$q1.total", 0 ] },
            "ab.b": { $ifNull: [ "$q2.total", 0 ] },
            "c.true": { $ifNull: [ "$q3.total", 0 ] },
            "c.false": { $ifNull: [ "$q4.total", 0 ] },
            d: "$q5.unique",
            "e.average": "$q6.average",
            "e.min": "$q6.min",
            "e.max": "$q6.max",
        }
    }
])

因此q1-q6只是单独的聚合管道。它们每个都返回结果数组,可以使用$arrayElemAt将其转换为单独的子文档。然后,您可以使用简单的$project将其重塑为最终结果。在没有值的情况下,使用$addToSet获取d的唯一值,并使用$ifNull替换那些计数,默认值为0