The 5-Minute Guide to Working with ESG Data on MongoDB
Rate this tutorial
MongoDB makes it incredibly easy to work with environmental, social, and corporate governance (ESG) data from multiple providers, analyze that data, and then visualize it.
In this quick guide, we will show you how MongoDB can:
- Move ESG data from different data sources to the document model.
- Easily incorporate new ESG source feeds to the document data model.
- Run advanced, aggregated queries on ESG data.
- Visualize ESG data.
- Manage different data types in a single document.
- Integrate geospatial data.
NOTE: An MSCI account and login is required to download the datasets linked to in this article. Dataset availability is dependent on MSCI product availability.
Our examples are drawn from real-life work with MongoDB clients in the financial services industry. Screenshots (apart from code snippets) are taken from MongoDB Compass, MongoDB’s GUI for querying, optimizing, and analyzing data.
The first step is to download the MSCI dataset, and import the MSCI .csv file (Figure 1) into MongoDB.
Even though MSCI’s data is in tabular format, MongoDB’s document data model allows you to import the data directly into a database collection and apply the data types as needed.
Figure 1. Importing the data using MongoDB’s Compass GUI
With the MSCI data imported into MongoDB, we can start discovering, querying, and visualizing it.
Source Data Set: MSCI ESG Accounting Governance Risk (AGR)
Collection:
accounting_governance_risk_agr_ratings
From MSCI - “ESG AGR uses a quantitative approach to identify risks in the financial reporting practices and accounting governance of publicly listed companies. Metrics contributing to the score include traditional fundamental ratios used to evaluate corporate strength and profitability, as well as forensic ratios.”
Fields/Data Info:
- The AGR (Accounting & Governance Risk) Rating consists of four groupings based on the AGR Percentile: Very Aggressive (1-10), Aggressive (11-35), Average (36-85), Conservative (86-100).
- The AGR (Accounting & Governance Risk) Percentile ranges from 1-100, with lower values representing greater risks.
In this example, we will count the number of AGR rated companies in Japan belonging to each AGR rating group (i.e., Very Aggressive, Aggressive, Average, and Conservative). To do this, we will use MongoDB’s aggregation pipeline to process multiple documents and return the results we’re after.
The aggregation pipeline presents a powerful abstraction for working with and analyzing data stored in the MongoDB database. The composability of the aggregation pipeline is one of the keys to its power. The design was actually modeled on the Unix pipeline, which allows developers to string together a series of processes that work together. This helps to simplify their application code by reducing logic, and when applied appropriately, a single aggregation pipeline can replace many queries and their associated network round trip times.
What aggregation stages will we use?
- The $match operator in MongoDB works as a filter. It filters the documents to pass only the documents that match the specified condition(s).
- The $group stage separates documents into groups according to a "group key," which, in this case, is the value of Agr_Rating.
- Additionally, at this stage, we can summarize the total count of those entities.
Combining the first two aggregation stages, we can filter the Issuer_Cntry_Domicile field to be equal to Japan — i.e., ”JP” — and group the AGR ratings.
As a final step, we will also sort the output of the total_count in descending order (hence the -1) and merge the results into another collection in the database of our choice, with the $merge operator.
1 [{ 2 $match: { 3 Issuer_Cntry_Domicile: 'JP' 4 } 5 }, { 6 $group: { 7 _id: '$Agr_Rating', 8 total_count: { 9 $sum: 1 10 }, 11 country: { 12 $first: '$Issuer_Cntry_Domicile' 13 } 14 } 15 }, { 16 $sort: { 17 total_count: -1 18 } 19 }, { 20 $merge: { 21 into: { 22 db: 'JP_DB', 23 coll: 'jp_agr_risk_ratings' 24 }, 25 on: '_id', 26 whenMatched: 'merge', 27 whenNotMatched: 'insert' 28 } 29 }]
The result and output collection
'jp_agr_risk_ratings'
can be seen below.Next, let’s visualize the results of Step 1 with MongoDB Charts, which is integrated into MongoDB. With Charts, there’s no need for developers to worry about finding a compatible data visualization tool, dealing with data movement, or data duplication when creating or sharing data visualizations.
Figure 2. Distribution of AGR rating in Japan
Let’s go a step further and group the results for multiple countries. We can add more countries — for instance, Japan and Hong Kong — and then $group and $count the results for them in Figure 3.
Figure 3. $match stage run in MongoDB Compass
Moving back to Charts, we can easily display the results comparing governance risks for Hong Kong and Japan, as shown in Figure 4.
Figure 4. Compared distribution of AGR ratings - Japan vs Hong Kong
From MSCI - “GeoQuant's Country Fundamental Risk Indicators fuses political and computer science to measure and predict political risk. GeoQuant's machine-learning software scrapes the web for large volumes of reputable data, news, and social media content. “
Fields/Data Info:
- Health (Health Risk) - Quality of/access to health care, resilience to disease
- IR (International Relations Risk) - Prevalence/likelihood of diplomatic, military, and economic conflict with other countries
- PolViol (Political Violence Risk) - Prevalence/likelihood of civil war, insurgency, terrorism
With the basics of MongoDB’s query framework understood, let’s move on to more complex queries, again using MongoDB’s aggregation pipeline capabilities.
With MongoDB’s document data model, we can nest documents within a parent document. In addition, we are able to perform query operations over those nested fields.
Imagine a scenario where we have two separate collections of ESG data, and we want to combine information from one collection into another, fetch that data into the result array, and further filter and transform the data.
We can do this using an aggregation pipeline.
Let’s say we want more detailed results for companies located in a particular country — for instance, by combining data from
focus_risk_scores
with our primary collection: accounting_governance_risk_agr_ratings
.
Figure 5. accounting_governance_risk_agr_ratings collection in MongoDB Compass
Figure 6. focus_risk_scores collection in MongoDB Compass
In order to do that, we use the $lookup stage, which adds a new array field to each input document. It contains the matching documents from the "joined" collection. This is similar to the joins used in relational databases. You may ask, "What is $lookup syntax?"
To perform an equality match between a field from the input documents with a field from the documents of the "joined" collection, the $lookup stage has this syntax:
1 { 2 $lookup: 3 { 4 from: <collection to join>, 5 localField: <field from the input documents>, 6 foreignField: <field from the documents of the "from" collection>, 7 as: <output array field> 8 } 9 }
In our case, we want to join and match the value of Issuer_Cntry_Domicile from the collection accounting_governance_risk_agr_ratings with the value of Country field from the collection focus_risk_scores, as shown in Figure 7.
Figure 7. $lookup stage run in MongoDB Compass
After performing the $lookup operation, we receive the data into the ‘result’ array field.
Imagine that at this point, we decide only to display Issuer_Name and Issuer_Cntry_Domicle from the first collection. We can do so with the $project operator and define the fields that we want to be visible for us in Figure 8.
Figure 8. $project stage run in MongoDB Compass
Additionally, we remove the result_.id field that comes from the original document from the other collection as we do not need it at this stage. Here comes the handy $unset stage.
Figure 9. $unset stage run in MongoDB Compass
With our data now cleaned up and viewable in one collection, we can go further and edit the data set with new custom fields and categories.
Updating fields
Let’s say we would like to set up new fields that categorize Health, IR, and PolViol lists separately.
To do so, we can use the $set operator. We use it to create new fields — health_risk, politcial_violance_risk, international_relations_risk — where each of the respective fields will consist of an array with only those elements that match the condition specified in $filter operator.
$filter has the following syntax:
1 { 2 $filter: 3 { 4 input: <array>, 5 as: <string>, 6 cond: <expression> 7 } 8 }
input — An expression that resolves to an array.
as — A name for the variable that represents each individual element of the input array.
cond — An expression that resolves to a boolean value used to determine if an element should be included in the output array. The expression references each element of the input array individually with the variable name specified in as.
In our case, we perform the $filter stage where the input we specify as “$result” array.
Why dollar sign and field name?
This prefixed field name with a dollar sign $ is used in aggregation expressions to access fields in the input documents (the ones from the previous stage and its result field).
Further, we name every individual element from that $result field as “metric”.
To resolve the boolean we define conditional expression, in our case, we want to run an equality match for a particular metric "$$metric.Risk" (following the "$$." syntax that accesses a specific field in the metric object).
And define and filter those elements to the appropriate value (“Health”, “PolViol”, “IR”).
1 cond: { 2 $eq: ["$$metric.Risk", "Health"], 3 }
The full query can be seen below in Figure 10.
Figure 10. $set stage and $filter operator run in MongoDB Compass
After we consolidate the fields that are interesting for us, we can remove redundant result array and use $unset operator once again to remove result field.
Figure 11. $unset stage run in MongoDB Compass
The next step is to calculate the average risk of every category (Health, International Relations, Political Violence) between country of origin where Company resides (“Country” field) and other countries (“Primary_Countries” field) with $avg operator within $set stage (as seen in Figure 12).
Figure 12. $set stage run in MongoDB Compass
And display only the companies whose average values are greater than 0, with a simple $match operation Figure 13.
Figure 13. $match stage run in MongoDB Compass
Save the data (merge into) and display the results in the chart.
Once again, we can use the $merge operator to save the result of the aggregation and then visualize it using MongoDB Charts Figure 14.
Figure 14. $merge stage run in MongoDB Compass
Let’s take our data set and create a chart of the Average Political Risk for each company, as displayed in Figure 15.
Figure 15. Average Political Risk per Company in MongoDB Atlas Charts
We can also create Risk Charts per category of risk, as seen in Figure 16.
Figure 16. average international risk per company in MongoDB Atlas Charts
Figure 17. average health risk per company in MongoDB Atlas Charts
Below is a snippet with all the aggregation operators mentioned in Scenario 2:
1 [ 2 { 3 $lookup: { 4 from: "focus_risk_scores", 5 localField: "Issuer_Cntry_Domicile", 6 foreignField: "Country", 7 as: "result", 8 }, 9 }, 10 { 11 $project: { 12 _id: 1, 13 Issuer_Cntry_Domicile: 1, 14 result: 1, 15 Issuer_Name: 1, 16 }, 17 }, 18 { 19 $unset: "result._id", 20 }, 21 { 22 $set: { 23 health_risk: { 24 $filter: { 25 input: "$result", 26 as: "metric", 27 cond: { 28 $eq: ["$$metric.Risk", "Health"], 29 }, 30 }, 31 }, 32 political_violence_risk: { 33 $filter: { 34 input: "$result", 35 as: "metric", 36 cond: { 37 $eq: ["$$metric.Risk", "PolViol"], 38 }, 39 }, 40 }, 41 international_relations_risk: { 42 $filter: { 43 input: "$result", 44 as: "metric", 45 cond: { 46 $eq: ["$$metric.Risk", "IR"], 47 }, 48 }, 49 }, 50 }, 51 }, 52 { 53 $unset: "result", 54 }, 55 { 56 $set: { 57 health_risk_avg: { 58 $avg: "$health_risk.risk_values", 59 }, 60 political_risk_avg: { 61 $avg: "$political_violence_risk.risk_values", 62 }, 63 international_risk_avg: { 64 $avg: "$international_relations_risk.risk_values", 65 }, 66 }, 67 }, 68 { 69 $match: { 70 health_risk_avg: { 71 $gt: 0, 72 }, 73 political_risk_avg: { 74 $gt: 0, 75 }, 76 international_risk_avg: { 77 $gt: 0, 78 }, 79 }, 80 }, 81 { 82 $merge: { 83 into: { 84 db: "testDB", 85 coll: "agr_avg_risks", 86 }, 87 on: "_id", 88 }, 89 }, 90 ]
From MSCI - “Elevate’s Supply Chain ESG Risk Ratings aggregates data from its verified audit database to the country level. The country risk assessment includes an overall score as well as 38 sub-scores organized under labor, health and safety, environment, business ethics, and management systems.”
ESG data processing requires the handling of a variety of structured and unstructured data consisting of financial, non-financial, and even climate-related geographical data. In this final scenario, we will combine data related to environmental scoring — especially wastewater, air, environmental indexes, and geo-locations data — and present them in a geo-spatial format to help business users quickly identify the risks.
MongoDB provides a flexible and powerful multimodel data management approach and includes the support of storing and querying geospatial data using GeoJSON objects or as legacy coordinate pairs. We shall see in this example how this can be leveraged for handling the often complex ESG data.
Firstly, let’s filter and group the data. Using $match and $group operators, we can filter and group the country per country and province, as shown in Figure 15 and Figure 16.
Figure 18. $match stage run in MongoDB Compass
Figure 19. $group stage run in MongoDB Compass
Now that we have the data broken out by region and country, in this case Vietnam, let’s display the information on a map.
It doesn’t matter that the original ESG data did not include comprehensive geospatial data or data in GeoJSON format, as we can simply augment our data set with the latitude and longitude for each region.
Using the $set operator, we can apply the logic for all regions of the data, as shown in Figure 20.
Leveraging the $switch operator, we evaluate a series of case expressions and set the coordinates of longitude and latitude for the particular province in Vietnam.
Figure 20. $set stage and $switch operator run in MongoDB Compass
Using MongoDB Charts’ built-in heatmap feature, we can now display the maximum air emission, environment management, and water waste metrics data for Vietnamese regions as a color-coded heat map.
Figure 21. heatmaps of Environment, Air Emission, Water Waste Indexes in Vietnam in MongoDB Atlas Charts
Below is a snippet with all the aggregation operators mentioned in Scenario 3:
1 [{ 2 $match: { 3 Country: { 4 $ne: 'null' 5 }, 6 Province: { 7 $ne: 'All' 8 } 9 } 10 }, { 11 $group: { 12 _id: { 13 country: '$Country', 14 province: '$Province' 15 }, 16 environment_management: { 17 $max: '$Environment_Management_Index_Elevate' 18 }, 19 air_emssion_index: { 20 $max: '$Air_Emissions_Index_Elevate' 21 }, 22 water_waste_index: { 23 $max: '$Waste_Management_Index_Elevate' 24 } 25 } 26 }, { 27 $project: { 28 country: '$_id.country', 29 province: '$_id.province', 30 environment_management: 1, 31 air_emssion_index: 1, 32 water_waste_index: 1, 33 _id: 0 34 } 35 }, { 36 $set: { 37 loc: { 38 $switch: { 39 branches: [ 40 { 41 'case': { 42 $eq: [ 43 '$province', 44 'Southeast' 45 ] 46 }, 47 then: { 48 type: 'Point', 49 coordinates: [ 50 105.8, 51 21.02 52 ] 53 } 54 }, 55 { 56 'case': { 57 $eq: [ 58 '$province', 59 'North Central Coast' 60 ] 61 }, 62 then: { 63 type: 'Point', 64 coordinates: [ 65 105.54, 66 18.2 67 ] 68 } 69 }, 70 { 71 'case': { 72 $eq: [ 73 '$province', 74 'Northeast' 75 ] 76 }, 77 then: { 78 type: 'Point', 79 coordinates: [ 80 105.51, 81 21.01 82 ] 83 } 84 }, 85 { 86 'case': { 87 $eq: [ 88 '$province', 89 'Mekong Delta' 90 ] 91 }, 92 then: { 93 type: 'Point', 94 coordinates: [ 95 105.47, 96 10.02 97 ] 98 } 99 }, 100 { 101 'case': { 102 $eq: [ 103 '$province', 104 'Central Highlands' 105 ] 106 }, 107 then: { 108 type: 'Point', 109 coordinates: [ 110 108.3, 111 12.4 112 ] 113 } 114 }, 115 { 116 'case': { 117 $eq: [ 118 '$province', 119 'Northwest' 120 ] 121 }, 122 then: { 123 type: 'Point', 124 coordinates: [ 125 103.1, 126 21.23 127 ] 128 } 129 }, 130 { 131 'case': { 132 $eq: [ 133 '$province', 134 'South Central Coast' 135 ] 136 }, 137 then: { 138 type: 'Point', 139 coordinates: [ 140 109.14, 141 13.46 142 ] 143 } 144 }, 145 { 146 'case': { 147 $eq: [ 148 '$province', 149 'Red River Delta' 150 ] 151 }, 152 then: { 153 type: 'Point', 154 coordinates: [ 155 106.3, 156 21.11 157 ] 158 } 159 } 160 ], 161 'default': null 162 } 163 } 164 } 165 }]
As we can see from the scenarios above, MongoDB’s out-of-the box tools and capabilities — including a powerful aggregation pipeline framework for simple or complex data processing, Charts for data visualization, geospatial data management, and native drivers — can easily and quickly combine different ESG-related resources and produce actionable insights.
MongoDB has a distinct advantage over relational databases when it comes to handling ESG data, negating the need to produce the ORM mapping for each data set.
Import any type of ESG data, model the data to fit your specific use case, and perform tests and analytics on that data with only a few commands.
To learn more about how MongoDB can help with your ESG needs, please visit our dedicated solution page.