MongoDB遍历文档键并求和值

3

我很新于MongoDb。因此,我的csv文件包含以下有关年度支出的数据。

{"Name": "Aruba",
   "Code": "ABW",
   "Type": "Country",
   "IndicatorName": "Military_expenditure",
   "1900": 0,
   "1961": 1,
   "1962": 0,
   "1963": 0,
   "1964": 0,
   "1965": 0,
   "1966": 0,
   "1967": 0,
   "1968": 0,
   "1969": 0
}, {
   "Name": "Afghanistan",
   "Code": "AFG",
   "Type": "Country",
   "IndicatorName": "Military_expenditure",
   "1900": 0,
   "1961": 100,
   "1962": 0,
   "1963": 0,
   "1964": 0,
   "1965": 0,
   "1966": 0,
   "1967": 0,
   "1968": 0,
   "1969": 0
}

然而,我需要获取以下两项的总开销:

  1. 每年的总开销,即:

阿鲁巴=1 >> (1900=0 + 1961=1......+ 1969=0} 阿富汗 = 100 >> (1900=0 + 1961=100......+ 1969=0}

  1. 各个国家的总开销=101

阿鲁巴 (1900=0 + 1961=1......+ 1969=0} + 阿富汗(1900=0 + 1961=100......+ 1969=0}

请问是否有人可以帮忙在MongoDb中进行上述计算?

不过,我已经编写了查询以按年份获取总和。

db.MiltryExpenditure.aggregate([

 { $match: { "Type":"Country" } },

 {$group:{_id : null,
 1969: { $sum: { "$toDouble":"$1969" }}
, _id : null,
 1960: { $sum: { 

"$toDouble":"$1960" }},
}}
])

但我不知道如何获得各国的总和,以及是否有一种归一化方法来获得按国家划分的总和,如果有,那将不胜感激。

请帮忙……


你只有这些年份或者更多的随机年数吗?另外你还有多少其他领域?也许可以使用编程语言代码轻松完成这项任务! - whoami - fakeFaceTrueSoul
我有1900年至2018年和265行(国家)的数据,我必须使用Mongo命令完成此任务。 - Udk
你是否有重复的文档,其中包含 "Name": "Afghanistan""Name": "Aruba" 这样的内容? - whoami - fakeFaceTrueSoul
不,我没有任何重复的。 - Udk
3个回答

2

$objectToArray 可以将您的 $$ROOT 对象转换为键值对数组。然后,您可以在该数组上应用 $filter 以仅获取表示年份的那些键值对。一旦数据集限制为年份,您可以运行 $unwind 以便逐个年份执行 $group

db.collection.aggregate([
    {
        $project: {
            _id: 0,
            years: { 
                $filter: { 
                    input: { $objectToArray: "$$ROOT" }, 
                    cond: { $and: [ { $gte: [ "$$this.k", "1900" ] }, { $lte: [ "$$this.k", "2020" ] } ] } 
                } 
            }
        }
    },
    {
        $unwind: "$years"
    },
    {
        $group: {
            _id: "$years.k",
            total: { $sum: "$years.v" }
        }
    },
    {
        $sort: { _id: 1 }
    }
])

Mongo Playground

按国家分组更容易,您可以运行$sum两次(首先通过文档总结所有年份,然后在$group内部再次汇总):

db.collection.aggregate([
    {
        $project: {
            _id: 0,
            Name: 1,
            years: { 
                $filter: { 
                    input: { $objectToArray: "$$ROOT" }, 
                    cond: { $and: [ { $gte: [ "$$this.k", "1900" ] }, { $lte: [ "$$this.k", "2020" ] } ] } 
                } 
            }
        }
    },
    {
        $group: {
            _id: "$Name",
            total: { $sum: { "$sum": "$years.v" } }
        }
    }
])

Mongo Playground (2)

编辑:如果每个国家只有一个文档,第二个查询可以缩短(可以去掉$group):

db.collection.aggregate([
    {
        $project: {
            _id: 0,
            Name: 1,
            Total: {
                $let: {
                    vars: { years: { 
                        $filter: { 
                            input: { $objectToArray: "$$ROOT" }, 
                            cond: { $and: [ { $gte: [ "$$this.k", "1900" ] }, { $lte: [ "$$this.k", "2020" ] } ] } 
                        } 
                    } },
                    in: { $sum: "$$years.v" }
                }
            }
        }
    }
])

2

Please try this :

db.yourCollection.aggregate([{ $match: { "Type": "Country" } },
{ $project: { _id: 0, Code: 0, IndicatorName: 0, Type: 0 } },
{
    $addFields: {
        onlyYears: {
            $filter: {
                input: { $objectToArray: "$$ROOT" },
                as: "item",
                cond: { $ne: ["$$item.k", 'Name'] }
            }
        }
    }
}, {
    $project: {
        Name: 1, count: {
            $reduce: {
                input: '$onlyYears',
                initialValue: 0,
                in: { $add: ["$$value", {"$toDouble": "$$this.v"}] }
            }
        }
    }
},
{ $group: { _id: '', count: { $sum: '$count' }, data: { $push: '$$ROOT' } } }
])

结果:

/* 1 */
{
    "_id" : "",
    "count" : 101.0,
    "data" : [ 
        {
            "Name" : "Aruba",
            "count" : 1.0
        }, 
        {
            "Name" : "Afghanistan",
            "count" : 100.0
        }
    ]
}

这给我一个语法错误,说$add仅支持数字或数据类型而不是字符串, 我认为这个错误是因为上传到集合的CSV数据将费用值识别为字符串。请问您能否帮忙包括从字符串转换为双精度的过程? - Udk
1
@Udk:根据支出的字符串值更新了代码!! - whoami - fakeFaceTrueSoul
你是指data中的Name吗?能否在此给我您的结果。 - whoami - fakeFaceTrueSoul
这是我得到的结果 { "_id" : "", "count" : 3240672793.3, "data" : [ { "Name" : "0", "count" : 1 }, { "Name" : "0", "count" : 3240672792.3 } ] } - Udk
1
@Udk:请在聊天室中尝试我的回答。 - whoami - fakeFaceTrueSoul
显示剩余5条评论

1
你可以尝试像这样,
    db.MiltryExpenditure.aggregate(
   [{
        "$match": {
            "Type": "Country"
        }
    },
    {
        "$group": {
            "_id": null,

            "1969": {
                "$sum": {
                    "$toDouble": "$1969"
                }
            },

            "1960": {
                "$sum": {
                    "$toDouble": "$1960"
                }
            },

            "totalSummation": {
                "$sum": {
                    "$add": [{
                        "$toDouble": "$1960"
                    }, {
                        "$toDouble": "$1961"
                    }]
                }
            }
        }
    }
])

这个代码给我一个错误,说“语法错误:元素列表后缺少]”我的语法:db.MiltryExpenditure.aggregate( [ { "$match": { "Type": "Country" } }, { "$group": {"_id": null,"1969": { "$sum": {"$toDouble": "$1969" }}, "1960": { "$sum": {"$toDouble": "$1960"}}, "totalSummation": {"$sum": {"$add": ["$toDouble":"$1960","$toDouble":"$1961" ]}} } } ]); - Udk
1
现在进行了修正的答案检查。 - Ashish Bakwad
你能否建议一下,我该如何从这个查询中获取前10个值? - Udk

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