在 mongodb 中,经过几个 $match 和 $project,我得到以下 2 个文件。我试图弄清楚如何将每个事件的每个组中每个团队的状态列表分组/计数在一起。简而言之,我需要知道每个州有多少支球队(0、1 或 2)。我从以下文件开始。
{
"_id" : "event1",
"groups" : [
{
"_id" : "group1",
"wlActive" : true,
"teams" : [
{"state" : NumberInt(2)},
{"state" : NumberInt(2)},
{"state" : NumberInt(1)},
{"state" : NumberInt(1)},
{"state" : NumberInt(1)},
{"state" : NumberInt(0)},
{"state" : NumberInt(0)}
]
},
{
"_id" : "group2",
"wlActive" : false,
"teams" : [
{"state" : NumberInt(2)},
{"state" : NumberInt(2)},
{"state" : NumberInt(1)},
{"state" : NumberInt(1)},
{"state" : NumberInt(1)},
{"state" : NumberInt(0)},
{"state" : NumberInt(0)}
]
}
]
},
{
"_id" : "event2",
"groups" : [
{
"_id" : "group3",
"wlActive" : true,
"teams" : [
{"state" : NumberInt(2)},
{"state" : NumberInt(2)},
{"state" : NumberInt(1)},
{"state" : NumberInt(1)},
{"state" : NumberInt(1)},
{"state" : NumberInt(0)},
{"state" : NumberInt(0)}
]
},
{
"_id" : "group4",
"wlActive" : false,
"teams" : [
{"state" : NumberInt(2)},
{"state" : NumberInt(2)},
{"state" : NumberInt(1)},
{"state" : NumberInt(1)},
{"state" : NumberInt(1)},
{"state" : NumberInt(0)},
{"state" : NumberInt(0)}
]
}
]
}
我希望最终得到的结果是这样的:
{
"_id" : "event1",
"groups" : [
{
"_id" : "group1",
"wlActive" : true,
"states":[
{"state":NumberInt(2), count:2},
{"state":NumberInt(1), count:3},
{"state":NumberInt(0), count:2}
}
},
{
"_id" : "group2",
"wlActive" : false,
"states":[
{"state":NumberInt(2), count:2},
{"state":NumberInt(1), count:3},
{"state":NumberInt(0), count:2}
}
}
]
},
{
"_id" : "event2",
"groups" : [
{
"_id" : "group3",
"wlActive" : true,
"states":[
{"state":NumberInt(2), count:2},
{"state":NumberInt(1), count:3},
{"state":NumberInt(0), count:2}
}
},
{
"_id" : "group4",
"wlActive" : false,
"states":[
{"state":NumberInt(2), count:2},
{"state":NumberInt(1), count:3},
{"state":NumberInt(0), count:2}
}
}
]
}
它不需要完全是这样,但只要我能得到每个团队状态的计数并为每个组保留字段,例如“wlActive”。我在这里看到过类似的例子,但我似乎无法解决这个问题。
最佳答案
您实际上可以使用 $addFields 来做到这一点或 $project
db.collection.aggregate([
{ "$addFields": {
"groups": {
"$map": {
"input": "$groups",
"in": {
"$mergeObjects": [
"$$this",
{ "teams": {
"$reduce": {
"input": "$$this.teams",
"initialValue": [ ],
"in": {
"$cond": {
"if": {
"$ne": [ { "$indexOfArray": ["$$value.state", "$$this.state"] }, -1 ]
},
"then": {
"$concatArrays": [
{ "$filter": {
"input": "$$value",
"as": "v",
"cond": { "$ne": [ "$$v.state", "$$this.state" ] }
}},
[{
"state": "$$this.state",
"count": { "$sum": [
{ "$arrayElemAt": [
"$$value.count",
{ "$indexOfArray": ["$$value.state", "$$this.state" ] }
]},
1
]}
}]
]
},
"else": {
"$concatArrays": [
"$$value",
[{ "state": "$$this.state", "count": 1 }]
]
}
}
}
}
}}
]
}
}
}
}}
])
这很复杂,基本上使用 $reduce “内联”作为 $group 的替代品管道运营商。
$reduce是工作的主要部分,因为它迭代每个数组项“减少”到另一个数组,键上有“分组”总数。它通过 $indexOfArray 在当前缩减结果中查找 state 的值来实现这一点。 .当找不到某些东西时(返回 -1 ),它会通过 $concatArrays 附加到当前结果。新的 state 和 count 为 1。这是 else 的情况。
当找到(then 情况)时,我们通过 $filter 从结果数组中删除匹配的元素。并从 $indexOfArray 的匹配索引中连接一个新元素并使用 $arrayElemAt 提取值.这给出了使用 $sum 添加的匹配元素的当前 count为了将计数增加 1。
当然,传统上您可以使用 $unwind 来做到这一点和 $group声明:
db.collection.aggregate([
{ "$unwind": "$groups" },
{ "$unwind": "$groups.teams" },
{ "$group": {
"_id": {
"_id": "$_id",
"gId": "$groups._id",
"wlActive": "$groups.wlActive",
"state": "$groups.teams.state"
},
"count": { "$sum": 1 }
}},
{ "$sort": { "_id": -1, "count": -1 } },
{ "$group": {
"_id": {
"_id": "$_id._id",
"gId": "$_id.gId",
"wlActive": "$_id.wlActive",
},
"teams": { "$push": { "state": "$_id.state", "count": "$count" } }
}},
{ "$group": {
"_id": "$_id._id",
"groups": {
"$push": {
"_id": "$_id.gId",
"wlActive": "$_id.wlActive",
"teams": "$teams"
}
}
}}
])
在这里$unwind用于将数组内容“展平”到单独的文档中。您将此执行到 teams 级别和 $group在复合键上,它标识唯一性到状态级别。
由于所有文档详细信息都是初始 $group 的一部分键,您删除了“唯一性” 的级别,这样teams 就变成了一个使用$push 的数组.为了回到原来的文件形式,另一个$group在文档的原始 _id 值和 $push 上完成重建 groups 数组。
这种形式可能“更容易”理解,但是它确实需要更长的运行时间和更多的资源。第一种形式是最佳,因为您实际上不需要 $group在现有文档中,您通常应该避免 $unwind除非绝对必要。即在所有文档中对state进行分组是必要的,但在单个文档中则不是。
两种方式基本上返回相同的结果:
{
"_id" : "event1",
"groups" : [
{
"_id" : "group1",
"wlActive" : true,
"teams" : [
{
"state" : 2,
"count" : 2
},
{
"state" : 1,
"count" : 3
},
{
"state" : 0,
"count" : 2
}
]
},
{
"_id" : "group2",
"wlActive" : false,
"teams" : [
{
"state" : 2,
"count" : 2
},
{
"state" : 1,
"count" : 3
},
{
"state" : 0,
"count" : 2
}
]
}
]
}
{
"_id" : "event2",
"groups" : [
{
"_id" : "group3",
"wlActive" : true,
"teams" : [
{
"state" : 2,
"count" : 2
},
{
"state" : 1,
"count" : 3
},
{
"state" : 0,
"count" : 2
}
]
},
{
"_id" : "group4",
"wlActive" : false,
"teams" : [
{
"state" : 2,
"count" : 2
},
{
"state" : 1,
"count" : 3
},
{
"state" : 0,
"count" : 2
}
]
}
]
}
就其值(value)而言,因为这不是真正的“聚合”文档中的任何内容,您可以简单地返回所有数据并“聚合”客户端代码中的数组项。
作为 mongo shell 的例子:
db.collection.find().map(doc => Object.assign({}, doc, {
_id: doc._id,
groups: doc.groups.map(g => Object.assign({}, g, {
_id: g._id,
wlActive: g.wlActive,
teams: ((input) => {
var obj = input.reduce((o, e) =>
(o.hasOwnProperty(e.state)) ?
Object.assign({} , o, { [e.state]: o[e.state]+1 })
: Object.assign({}, o, { [e.state]: 1 }), {});
return Object.keys(obj)
.map(k => ({ state: parseInt(k), count: obj[k] }))
.sort((a,b) => b.state - a.state);
})(g.teams)
}))
}))
关于mongodb - 在保留根字段的同时对子文档进行分组/计数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54992837/
很好奇,就使用rubyonrails自动化单元测试而言,你们正在做什么?您是否创建了一个脚本来在cron中运行rake作业并将结果邮寄给您?git中的预提交Hook?只是手动调用?我完全理解测试,但想知道在错误发生之前捕获错误的最佳实践是什么。让我们理所当然地认为测试本身是完美无缺的,并且可以正常工作。下一步是什么以确保他们在正确的时间将可能有害的结果传达给您? 最佳答案 不确定您到底想听什么,但是有几个级别的自动代码库控制:在处理某项功能时,您可以使用类似autotest的内容获得关于哪些有效,哪些无效的即时反馈。要确保您的提
在控制台中反复尝试之后,我想到了这种方法,可以按发生日期对类似activerecord的(Mongoid)对象进行分组。我不确定这是完成此任务的最佳方法,但它确实有效。有没有人有更好的建议,或者这是一个很好的方法?#eventsisanarrayofactiverecord-likeobjectsthatincludeatimeattributeevents.map{|event|#converteventsarrayintoanarrayofhasheswiththedayofthemonthandtheevent{:number=>event.time.day,:event=>ev
我正在编写一个包含C扩展的gem。通常当我写一个gem时,我会遵循TDD的过程,我会写一个失败的规范,然后处理代码直到它通过,等等......在“ext/mygem/mygem.c”中我的C扩展和在gemspec的“扩展”中配置的有效extconf.rb,如何运行我的规范并仍然加载我的C扩展?当我更改C代码时,我需要采取哪些步骤来重新编译代码?这可能是个愚蠢的问题,但是从我的gem的开发源代码树中输入“bundleinstall”不会构建任何native扩展。当我手动运行rubyext/mygem/extconf.rb时,我确实得到了一个Makefile(在整个项目的根目录中),然后当
我有一个表单,其中有很多字段取自数组(而不是模型或对象)。我如何验证这些字段的存在?solve_problem_pathdo|f|%>... 最佳答案 创建一个简单的类来包装请求参数并使用ActiveModel::Validations。#definedsomewhere,atthesimplest:require'ostruct'classSolvetrue#youcouldevencheckthesolutionwithavalidatorvalidatedoerrors.add(:base,"WRONG!!!")unlesss
我想向我的Controller传递一个参数,它是一个简单的复选框,但我不知道如何在模型的form_for中引入它,这是我的观点:{:id=>'go_finance'}do|f|%>Transferirde:para:Entrada:"input",:placeholder=>"Quantofoiganho?"%>Saída:"output",:placeholder=>"Quantofoigasto?"%>Nota:我想做一个额外的复选框,但我该怎么做,模型中没有一个对象,而是一个要检查的对象,以便在Controller中创建一个ifelse,如果没有检查,请帮助我,非常感谢,谢谢
这是一道面试题,我没有答对,但还是很好奇怎么解。你有N个人的大家庭,分别是1,2,3,...,N岁。你想给你的大家庭拍张照片。所有的家庭成员都排成一排。“我是家里的friend,建议家庭成员安排如下:”1岁的家庭成员坐在这一排的最左边。每两个坐在一起的家庭成员的年龄相差不得超过2岁。输入:整数N,1≤N≤55。输出:摄影师可以拍摄的照片数量。示例->输入:4,输出:4符合条件的数组:[1,2,3,4][1,2,4,3][1,3,2,4][1,3,4,2]另一个例子:输入:5输出:6符合条件的数组:[1,2,3,4,5][1,2,3,5,4][1,2,4,3,5][1,2,4,5,3][
我知道我可以指定某些字段来使用pluck查询数据库。ids=Item.where('due_at但是我想知道,是否有一种方法可以指定我想避免从数据库查询的某些字段。某种反拔?posts=Post.where(published:true).do_not_lookup(:enormous_field) 最佳答案 Model#attribute_names应该返回列/属性数组。您可以排除其中一些并传递给pluck或select方法。像这样:posts=Post.where(published:true).select(Post.attr
我已经构建了一些serverspec代码来在多个主机上运行一组测试。问题是当任何测试失败时,测试会在当前主机停止。即使测试失败,我也希望它继续在所有主机上运行。Rakefile:namespace:specdotask:all=>hosts.map{|h|'spec:'+h.split('.')[0]}hosts.eachdo|host|begindesc"Runserverspecto#{host}"RSpec::Core::RakeTask.new(host)do|t|ENV['TARGET_HOST']=hostt.pattern="spec/cfengine3/*_spec.r
我们的git存储库中目前有一个Gemfile。但是,有一个gem我只在我的环境中本地使用(我的团队不使用它)。为了使用它,我必须将它添加到我们的Gemfile中,但每次我checkout到我们的master/dev主分支时,由于与跟踪的gemfile冲突,我必须删除它。我想要的是类似Gemfile.local的东西,它将继承从Gemfile导入的gems,但也允许在那里导入新的gems以供使用只有我的机器。此文件将在.gitignore中被忽略。这可能吗? 最佳答案 设置BUNDLE_GEMFILE环境变量:BUNDLE_GEMFI
这似乎非常适得其反,因为太多的gem会在window上破裂。我一直在处理很多mysql和ruby-mysqlgem问题(gem本身发生段错误,一个名为UnixSocket的类显然在Windows机器上不能正常工作,等等)。我只是在浪费时间吗?我应该转向不同的脚本语言吗? 最佳答案 我在Windows上使用Ruby的经验很少,但是当我开始使用Ruby时,我是在Windows上,我的总体印象是它不是Windows原生系统。因此,在主要使用Windows多年之后,开始使用Ruby促使我切换回原来的系统Unix,这次是Linux。Rub