如何在Mongodb中使用聚合在响应的输出上创建数组 [英] how to create an array on the output of a response using aggregate in Mongodb

查看:113
本文介绍了如何在Mongodb中使用聚合在响应的输出上创建数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的收藏夹中有一个具有以下结构的对象列表:

[
 {
    "country": "colombia",
    "city":"medellin",
    "calification": [
        {
            "_id": 1,
            "stars": 5
        },
        {
            "_id": 2,
            "stars": 3
        }
    ]
},
{
    "country": "colombia",
    "city":"manizales",
    "calification": [
        {
            "_id": 1,
            "stars": 5
        },
        {
            "_id": 2,
            "stars": 5
        }
    ]
},

{
    "country": "argentina",
    "city":"buenos aires",
    "calification": [
        {
            "_id": 1,
            "stars": 5
        },
    ]
},
{
    "country": "perú",
    "city":"cusco",
    "calification": [
        {
            "_id": 3,
            "stars": 3
        },
    ]
  }
]

我正在尝试制作一个过滤器,以便输出的数量是每个国家/地区的数组.这是我想要的输出示例.

avg将是结果sum'stars'/calification.length

{
  "colombia": [
    {
      "city": "medellin",
      "avg": 4,
      "calification": [
        {
          "_id": 1,
          "stars": 5
        },
        {
          "_id": 2,
          "stars": 3
        }
      ]
    },
    {
      "city": "manizales",
      "avg": 5,
      "calification": [
        {
          "_id": 1,
          "stars": 5
        },
        {
          "_id": 2,
          "stars": 3
        }
      ]
    }
  ],
  "argentina": {
    "city": "buenos aires",
    "avg": 5,
    "calification": [
      {
        "_id": 1,
        "stars": 5
      }
    ]
  },
  "peru": {
    "city": "cusco",
    "avg": 4,
    "calification": [
      {
        "_id": 1,
        "stars": 4
      }
    ]
  }
}

我正在尝试这样做:

    Alcalde.aggregate([

        {
            $addFields: {
                colombia: {
                    "$push": {

                        "$cond": [{ $eq: ["$country", "'Colombia'"] }, true, null]


                    }


                }

            }
        },
        {
            $project: { colombia: "$colombia" }
        }
    ]

我该怎么办

解决方案

我们可以使其更加优雅.

MongoDB具有 $ avg 运算符,让我们使用它.另外,我们可以使用$group运算符将同一country的城市分组.

最后,应用 $ replaceRoot + $ arrayToObject **我们将转换为所需结果.

**这是因为我们不能使用这样的表达式:{"$country":"$city"}

$replaceRoot                                 $arrayToObject

data : {              {                  [                             {
  "key" : "val",  -->   "key" : "val",     {k:"key", v: "val"},  -->     "key" : "val",
  "key2" : "val2"       "key2" : "val2"    {k:"key2", v: "val2"}         "key2" : "val2"
}                     }                  ]                             }


尝试一下:

Alcalde.aggregate([
  {
    $group: {
      _id: "$country",
      city: {
        $push: {
          "city": "$city",
          "avg": { $avg: "$calification.stars"},
          "calification": "$calification"
        }
      }
    }
  },
  {
    $replaceRoot: {
      newRoot: {
        $arrayToObject: [ [{ "k": "$_id", "v": "$city"}] ]
      }
    }
  }
])

MongoPlayground

填充city内部对象的通用方法

$$ROOT是用于存储根文档的变量
$mergeObjects向最终对象添加/覆盖字段

Alcalde.aggregate([
  {
    $group: {
      _id: "$country",
      city: {
        $push: {
          $mergeObjects: [
            "$$ROOT",
            {
              "avg": { "$avg": "$calification.stars" }
            }
          ]
        }
      }
    }
  },
  {
    $project: {
      "city.country": 0
    }
  },
  {
    $replaceRoot: {
      newRoot: {
        $arrayToObject: [
          [ { "k": "$_id", "v": "$city" } ]
        ]
      }
    }
  }
])

MongoPlayground

I have in my collection a list of objects with this structure:

[
 {
    "country": "colombia",
    "city":"medellin",
    "calification": [
        {
            "_id": 1,
            "stars": 5
        },
        {
            "_id": 2,
            "stars": 3
        }
    ]
},
{
    "country": "colombia",
    "city":"manizales",
    "calification": [
        {
            "_id": 1,
            "stars": 5
        },
        {
            "_id": 2,
            "stars": 5
        }
    ]
},

{
    "country": "argentina",
    "city":"buenos aires",
    "calification": [
        {
            "_id": 1,
            "stars": 5
        },
    ]
},
{
    "country": "perú",
    "city":"cusco",
    "calification": [
        {
            "_id": 3,
            "stars": 3
        },
    ]
  }
]

I am trying to make a filter so that the output is an amount of arrays for each country. this is the example of the output i want.

avg would be result sum 'stars'/ calification.length

{
  "colombia": [
    {
      "city": "medellin",
      "avg": 4,
      "calification": [
        {
          "_id": 1,
          "stars": 5
        },
        {
          "_id": 2,
          "stars": 3
        }
      ]
    },
    {
      "city": "manizales",
      "avg": 5,
      "calification": [
        {
          "_id": 1,
          "stars": 5
        },
        {
          "_id": 2,
          "stars": 3
        }
      ]
    }
  ],
  "argentina": {
    "city": "buenos aires",
    "avg": 5,
    "calification": [
      {
        "_id": 1,
        "stars": 5
      }
    ]
  },
  "peru": {
    "city": "cusco",
    "avg": 4,
    "calification": [
      {
        "_id": 1,
        "stars": 4
      }
    ]
  }
}

I am trying to do this:

    Alcalde.aggregate([

        {
            $addFields: {
                colombia: {
                    "$push": {

                        "$cond": [{ $eq: ["$country", "'Colombia'"] }, true, null]


                    }


                }

            }
        },
        {
            $project: { colombia: "$colombia" }
        }
    ]

how can i do it

解决方案

We can make it more elegant.

MongoDB has $avg operator, let's use it. Also, we can use $group operator to group cities for the same country.

At the end, applying $replaceRoot + $arrayToObject** we transform into desired result.

** it's because we cannot use such expression: {"$country":"$city"}

$replaceRoot                                 $arrayToObject

data : {              {                  [                             {
  "key" : "val",  -->   "key" : "val",     {k:"key", v: "val"},  -->     "key" : "val",
  "key2" : "val2"       "key2" : "val2"    {k:"key2", v: "val2"}         "key2" : "val2"
}                     }                  ]                             }


Try this one:

Alcalde.aggregate([
  {
    $group: {
      _id: "$country",
      city: {
        $push: {
          "city": "$city",
          "avg": { $avg: "$calification.stars"},
          "calification": "$calification"
        }
      }
    }
  },
  {
    $replaceRoot: {
      newRoot: {
        $arrayToObject: [ [{ "k": "$_id", "v": "$city"}] ]
      }
    }
  }
])

MongoPlayground

EDIT: Generic way to populate city inner object

$$ROOT is variable which stores root document
$mergeObjects adds / override fields to final object

Alcalde.aggregate([
  {
    $group: {
      _id: "$country",
      city: {
        $push: {
          $mergeObjects: [
            "$$ROOT",
            {
              "avg": { "$avg": "$calification.stars" }
            }
          ]
        }
      }
    }
  },
  {
    $project: {
      "city.country": 0
    }
  },
  {
    $replaceRoot: {
      newRoot: {
        $arrayToObject: [
          [ { "k": "$_id", "v": "$city" } ]
        ]
      }
    }
  }
])

MongoPlayground

这篇关于如何在Mongodb中使用聚合在响应的输出上创建数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆