Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/mongodb/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 在一个查询中为每个属性分组不同的值和计数_Javascript_Mongodb_Mongodb Query_Aggregation Framework - Fatal编程技术网

Javascript 在一个查询中为每个属性分组不同的值和计数

Javascript 在一个查询中为每个属性分组不同的值和计数,javascript,mongodb,mongodb-query,aggregation-framework,Javascript,Mongodb,Mongodb Query,Aggregation Framework,我有个人资料收集中的数据 [ { name: "Harish", gender: "Male", caste: "Vokkaliga", education: "B.E" }, { name: "Reshma", gender: "Female", caste: "Vokkaliga", education: "B.E" }, {

我有个人资料收集中的数据

[
    {
        name: "Harish",
        gender: "Male",
        caste: "Vokkaliga",
        education: "B.E"
    },
    {
        name: "Reshma",
        gender: "Female",
        caste: "Vokkaliga",
        education: "B.E"
    },
    {
        name: "Rangnath",
        gender: "Male",
        caste: "Lingayath",
        education: "M.C.A"
    },
    {
        name: "Lakshman",
        gender: "Male",
        caste: "Lingayath",
        education: "B.Com"
    },
    {
        name: "Reshma",
        gender: "Female",
        caste: "Lingayath",
        education: "B.E"
    }
]
这里我需要计算不同性别的总人数,不同种姓的总人数和不同教育的总人数。 预期o/p

{
    gender: [{
        name: "Male",
        total: "3"
    },
    {
        name: "Female",
        total: "2"
    }],
    caste: [{
        name: "Vokkaliga",
        total: "2"
    },
    {
        name: "Lingayath",
        total: "3"
    }],
    education: [{
        name: "B.E",
        total: "3"
    },
    {
        name: "M.C.A",
        total: "1"
    },
    {
        name: "B.Com",
        total: "1"
    }]
}

使用mongodb聚合如何才能获得预期结果。

根据可用版本的不同,有不同的方法,但它们基本上都会分解为将文档字段转换为“数组”中的单独文档,然后“展开”该数组包含并执行连续阶段,以累积输出总计和数组

MongoDB 3.4.4及以上版本 最新版本具有特殊的运算符,如and,它可以使从源文档到初始“数组”的传输比早期版本更具动态性:

db.profile.aggregate([
  { "$project": { 
     "_id": 0,
     "data": { 
       "$filter": {
         "input": { "$objectToArray": "$$ROOT" },
         "cond": { "$in": [ "$$this.k", ["gender","caste","education"] ] }
       }   
     }
  }},
  { "$unwind": "$data" },
  { "$group": {
    "_id": "$data",
    "total": { "$sum": 1 }  
  }},
  { "$group": {
    "_id": "$_id.k",
    "v": {
      "$push": { "name": "$_id.v", "total": "$total" } 
    }  
  }},
  { "$group": {
    "_id": null,
    "data": { "$push": { "k": "$_id", "v": "$v" } }
  }},
  { "$replaceRoot": {
    "newRoot": {
      "$arrayToObject": "$data"
    }
  }}
])
因此,使用将初始文档制作成一个由其键和值组成的数组,作为结果对象数组中的
“k”
“v”
键。我们在这里申请是为了按“键”进行选择。这里使用的是我们想要的键列表,但这可以更动态地用作键列表,以便在更短的地方“排除”。它只是使用逻辑运算符来评估条件

这里的结束阶段使用,并且由于中间的所有操作和“分组”仍然保持
“k”
“v”
形式,因此我们在这里使用将结果中的“对象数组”提升为输出中顶层文档的“键”

MongoDB 3.6$mergeObjects 在这里,MongoDB 3.6包含了一个额外的折痕,它也可以用作管道阶段中的,因此替换了,并使最终的只需将
“data”
键改为返回文档的“root”:

db.profile.aggregate([
  { "$project": { 
     "_id": 0,
     "data": { 
       "$filter": {
         "input": { "$objectToArray": "$$ROOT" },
         "cond": { "$in": [ "$$this.k", ["gender","caste","education"] ] }
       }   
     }
  }},
  { "$unwind": "$data" },
  { "$group": { "_id": "$data", "total": { "$sum": 1 } }},
  { "$group": {
    "_id": "$_id.k",
    "v": {
      "$push": { "name": "$_id.v", "total": "$total" } 
    }  
  }},
  { "$group": {
    "_id": null,
    "data": {
      "$mergeObjects": {
        "$arrayToObject": [
          [{ "k": "$_id", "v": "$v" }]
        ] 
      }
    }  
  }},
  { "$replaceRoot": { "newRoot": "$data"  } }
])
这与整体演示的内容并没有太大区别,只是演示了如何以这种方式使用,并且在分组键不同的情况下可能很有用,我们不希望最终“合并”到对象的根空间

请注意,仍然需要将“值”转换回“键”的名称,但我们只是在累积期间而不是在分组之后进行,因为新的累积允许键的“合并”

MongoDB 3.2 将其恢复为一个版本,或者即使您的MongoDB 3.4.x版本低于3.4.4版本,我们仍然可以使用其中的大部分内容,但我们以更静态的方式处理阵列的创建,以及以不同的方式处理输出的最终“转换”,因为我们没有聚合运算符:

db.profile.aggregate([
  { "$project": {
    "data": [
      { "k": "gender", "v": "$gender" },
      { "k": "caste", "v": "$caste" },
      { "k": "education", "v": "$education" }
    ]
  }},
  { "$unwind": "$data" },
  { "$group": {
    "_id": "$data",
    "total": { "$sum": 1 }  
  }},
  { "$group": {
    "_id": "$_id.k",
    "v": {
      "$push": { "name": "$_id.v", "total": "$total" } 
    }  
  }},
  { "$group": {
    "_id": null,
    "data": { "$push": { "k": "$_id", "v": "$v" } }
  }},
  /*
  { "$replaceRoot": {
    "newRoot": {
      "$arrayToObject": "$data"
    }
  }}
  */
]).map( d => 
  d.data.map( e => ({ [e.k]: e.v }) )
    .reduce((acc,curr) => Object.assign(acc,curr),{})
)
这是完全相同的事情,除了将文档动态转换为数组之外,我们实际上“显式”地使用相同的
“k”
“v”
符号指定每个数组成员。实际上,在这一点上只保留约定的键名,因为这里的聚合运算符都不依赖于此

此外,我们没有使用,只是做了与前面的管道阶段实现完全相同的事情,而是使用客户机代码。所有MongoDB驱动程序都有一些实现来启用“游标转换”。在这个shell中,我们使用和的基本JavaScript函数获取输出,并再次将数组内容提升为返回的顶级文档的键

MongoDB 2.6 回到MongoDB 2.6来介绍两者之间的版本,这里唯一改变的是使用和a for input以及数组声明:

db.profile.aggregate([
  { "$project": {
    "data": {
      "$map": {
        "input": { "$literal": ["gender","caste", "education"] },
        "as": "k",
        "in": {
          "k": "$$k",
          "v": {
            "$cond": {
              "if": { "$eq": [ "$$k", "gender" ] },
              "then": "$gender",
              "else": {
                "$cond": {
                  "if": { "$eq": [ "$$k", "caste" ] },
                  "then": "$caste",
                  "else": "$education"
                }
              }    
            }
          }    
        }
      }
    }
  }},
  { "$unwind": "$data" },
  { "$group": {
    "_id": "$data",
    "total": { "$sum": 1 }  
  }},
  { "$group": {
    "_id": "$_id.k",
    "v": {
      "$push": { "name": "$_id.v", "total": "$total" } 
    }  
  }},
  { "$group": {
    "_id": null,
    "data": { "$push": { "k": "$_id", "v": "$v" } }
  }},
  /*
  { "$replaceRoot": {
    "newRoot": {
      "$arrayToObject": "$data"
    }
  }}
  */
])
.map( d => 
  d.data.map( e => ({ [e.k]: e.v }) )
    .reduce((acc,curr) => Object.assign(acc,curr),{})
)
因为这里的基本思想是“迭代”提供的字段名数组,所以实际的赋值是通过“嵌套”语句来实现的。对于三种可能的结果,这意味着只有一个嵌套,以便为每个结果“分支”

3.4版本的现代MongoDB使这种分支变得更简单,但这证明了逻辑始终是可能的,并且自从MongoDB 2.2引入聚合框架以来,操作符一直存在

同样,游标结果上的相同转换也适用,因为这里没有什么新的东西,大多数编程语言都有能力这么做多年,如果不是从一开始

当然,基本过程甚至可以追溯到MongoDB 2.2,但只是以不同的方式应用数组创建。但目前还不应该有人在2.8下运行MongoDB,即使是3.0的官方支持也很快就要用完了


输出 为了可视化,在最后一次“转换”完成之前,此处演示的所有管道的输出具有以下形式:

然后通过或光标变换(如图所示),结果变为:

/* 1 */
{
    "gender" : [ 
        {
            "name" : "Male",
            "total" : 3.0
        }, 
        {
            "name" : "Female",
            "total" : 2.0
        }
    ],
    "education" : [ 
        {
            "name" : "M.C.A",
            "total" : 1.0
        }, 
        {
            "name" : "B.E",
            "total" : 3.0
        }, 
        {
            "name" : "B.Com",
            "total" : 1.0
        }
    ],
    "caste" : [ 
        {
            "name" : "Lingayath",
            "total" : 3.0
        }, 
        {
            "name" : "Vokkaliga",
            "total" : 2.0
        }
    ]
}

因此,虽然我们可以将一些新的、奇特的运算符放入聚合管道中,但最常见的用例是这些“管道末端转换”在这种情况下,我们不妨对返回的游标结果中的每个文档执行相同的转换。

提供的答案中是否有您认为无法解决您的问题的内容?如果是,请对答案进行评论,以澄清哪些问题需要解决,哪些问题尚未解决。如果它确实回答了您提出的问题,那么请注意您提出的问题。抱歉,这是我一直在寻找的问题。谢谢您的帮助Hi@neil我需要您的帮助,我有更多的要求为上述结果应用过滤器
/* 1 */
{
    "gender" : [ 
        {
            "name" : "Male",
            "total" : 3.0
        }, 
        {
            "name" : "Female",
            "total" : 2.0
        }
    ],
    "education" : [ 
        {
            "name" : "M.C.A",
            "total" : 1.0
        }, 
        {
            "name" : "B.E",
            "total" : 3.0
        }, 
        {
            "name" : "B.Com",
            "total" : 1.0
        }
    ],
    "caste" : [ 
        {
            "name" : "Lingayath",
            "total" : 3.0
        }, 
        {
            "name" : "Vokkaliga",
            "total" : 2.0
        }
    ]
}